jzoj3505NOIP2013模拟11.4A组组合逆元积木
Posted SSL_ZZL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jzoj3505NOIP2013模拟11.4A组组合逆元积木相关的知识,希望对你有一定的参考价值。
【NOIP2013模拟11.4A组】积木
题面
Description
小A正在搭积木。有N个位置可以让小A使用,初始高度都为0。小A每次搭积木的时候,都会选定一个拥有相同高度的区间[A…B],然后将位置[A+1…B-1]上的所有积木的高度加一。不幸的是,小A把积木搭好之后没多久,小A调皮的弟弟就将其中若干个位置上的积木弄倒了。小A想知道他原来的积木是如何摆放的,所以他求助于你,请你告诉他原来有多少种可能的摆法。
Input
第一行为一个正整数N,表示小A有N个位置。
第二行有N个由空格分隔的整数Hi,表示第i个位置的积木高度。-1表示这个位置上的积木已经被弄倒了。
Output
唯一的一行,输出包括可能的摆法mod 1,000,000,007的结果。
Sample Input
输入1:
3
-1 2 -1
输入2:
3
-1 -1 -1
输入3:
6
-1 -1 -1 2 -1 -1
Sample Output
输出1:
0
输出2:
2
输出3:
3
Data Constraint
对于50%的数据 1<=N<=1000 -1<=Hi<=1000
对于80%的数据 1<=N<=10000
对于100%的数据 1<=N<=20000 -1<=Hi<=10000
Source / Author: brick by 广州二中
解题思路
看到一堆人DP水过去了巨心动
设
f
i
,
j
f_{i,j}
fi,j为到i位置,高度为j的方案数,加上一堆奇奇怪怪的操作
结果搞了一上午没搞出来,笑着笑着就哭了((((((
于是被迫搞正解((((((
对答案数有贡献的一定都是-1,那么就可以把-1段的答案求出来然后乘起来
(图画的有点大了((((((()
从x走到y,有三种方向可选——上(u)、下(d)、平移(r),枚举u,那么d = high[x] + u - high[y](上升和下降最后一定要在y的高度,不然就不可能形成到y的路线),u和d都知道了,r = y - x - u - d
考虑方案,现在u、d、r的数量都已知,那就是个组合数学的问题了
C
y
−
x
u
C_{y - x}^{u}
Cy−xu是u的方案数,
C
y
−
x
−
u
d
C_{y - x - u}^{d}
Cy−x−ud是d的方案数,前两个已知,r方案数就只能是1了
C
y
−
x
u
⋅
C
y
−
x
−
u
d
⋅
1
C_{y - x}^{u}·C_{y - x - u}^{d}·1
Cy−xu⋅Cy−x−ud⋅1
但这其中还有不合法的方案数,路线走到0下了(积木总不能叠到小于0吧(doge))
考虑求出不合法的方案数,用 总方案数 - 不合法方案数 = 答案
作y’是y对于-1线的对称点
x到y’的路线方案数一定是不合法的方案数
- 一定经过-1=》一定不合法
- 将 -1线下的路线 折叠到-1线上,发现一定能到y点=》一定在总方案数中
此时出现大问题???(没错又是数论的锅)
C
n
m
%
P
=
A
n
m
A
m
m
%
P
=
n
!
m
!
⋅
(
n
−
m
)
!
%
P
C_n^m \\% P = \\frac{A_n^m}{A_m^m} \\% P = \\frac{n!}{m!·(n-m)!} \\% P
Cnm%P=AmmAnm%P=m!⋅(n−m)!n!%P
如果直接除直接炸飞天,于是需要用逆元((((((
数论补充站
快速幂求逆元模板
话说之前讲座学的是线性求,但是没打过((((((
Code
95pts
就是一直在卡啊TOT
#include <iostream>
#include <cstring>
#include <cstdio>
#define ll unsigned long long
using namespace std;
const int maxn = 20100;
const ll P = 1000000007;
int n, a[maxn], sta;
ll f[2][maxn];
int main() {
freopen("brick.in", "r", stdin);
freopen("brick.out", "w", stdout);
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
if(a[n] > 0) {
printf("0");
return 0;
}
f[1][0] = 1, sta = 1;
for(int i = 2; i <= n; i++) {
int now = i % 2, be = (i + 1) % 2; //滚动数组,卡空间
if(i <= n / 2 + 1) sta++; //算出高度,卡内存
else sta--;
for(int j = 0; j <= sta + 1; j++) f[now][j] = 0;
if(a[i] > -1) {
f[now][a[i]] = f[be][a[i] - 1] + f[be][a[i]] + f[be][a[i] + 1]; //已有积木高度,高度固定
if(i % 20 == 0) f[now][a[i]] %= P; //每20次%P,卡时间
continue;
}
for(int j = 0; j <= sta; j++) {
f[now][j] = f[be][j - 1] + f[be][j] + f[be][j + 1]; //上、下、平移
if(i % 20 == 0) f[now][j] %= P;
}
}
printf("%lld", f[n % 2][0] % P);
}
100pts
#include <iostream>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const ll P = 1000000007;
ll n, a[20100], x, y, d, u, r, f[20100], answer = 1;
ll ny(ll a, ll k) { //求逆元
ll ans = 1;
a %= P;
while(k) {
if(k & 1)ans = ans * a % P;
k >>= 1;
a = a * a % P;
}
return ans;
}
ll C(ll m, ll n) { //求解C
if(m == 0) return 1;
return (f[n] % P * ny(f[m] * f[n - m] % P, P - 2) % P);
}
int main() {
// freopen("brick.in", "r", stdin);
// freopen("brick.out", "w", stdout);
scanf("%lld", &n);
f[1] = f[0] = 1;
for(int i = 2; i <= n; i++) f[i] = f[i - 1] * (ll)i % P; //预处理阶乘
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
if(a[1] > 0 || a[n] > 0) {
printf("0");
return 0;
}
a[1] = a[n] = 0;
for(int i = 1; i < n; i++)
if(a[i] != -1 && a[i + 1] != -1 && abs(a[i] - a[i + 1]) > 1) {
printf("0");
return 0;
}
//************************************************************
//以上均为预处理、判不合法等
//************************************************************
x = 1;
for(int i = 2; i <= n; i++) {
if(a[i] == -1) continue;
y = i;
ll ans = 0;
for(int u = 0; u <= y - x; u++) {
d = a[x] + u - a[y], r = y - x - u - d;
if(d < 0 || r < 0) continue;
ans = (ans + C(u, u + d + r) * C(d, d + r) % P) % P; //合法方案数
}
ll ans_ = 0, ls = a[y];
a[y] = -a[y] - 2;
for(int u = 0; u <= y - x; u++) {
d = a[x] + u - a[y], r = y - x - u - d;
if(d < 0 || r < 0) continue;
ans_ = (ans_ + C(u, y - x) * C(d, y - x - u) % P) % P; //不合法方案数
}
a[y] = ls, x = y;
answer = answer * (ans - ans_ + P) % P; //不知道为什么要加P,但fy大爷说要,于是我加上就过了
}
printf("%lld", answer);
}
以上是关于jzoj3505NOIP2013模拟11.4A组组合逆元积木的主要内容,如果未能解决你的问题,请参考以下文章
jzoj3523NOIP2013模拟11.7A组树上倍增JIH的玩偶(tree)
jzoj3528NOIP2013模拟11.7A组数学拓扑DP图书馆(library)
jzoj3510NOIP2013模拟11.5B组DAY 1 (7.12)DP最短路径(path)
jzoj3508NOIP2013模拟11.5B组DAY 1 (7.12)HASH好元素(good)