PE 427

来源:互联网 发布:cygwin编译linux程序 编辑:程序博客网 时间:2024/05/17 22:31

题目大意:设 S 为长度为 n,元素大小为 1 到 n 的整数的排列集合,L(X) 为排列 X 中连续值相同的最长长度,求 X|SL(S),其中 n=7500000

F[n][k] 表示长度为 n 的序列,L < k 的方案数
易得递推式

F[n][k]=F[n1][k]nF[nk][k](n1)

第二维都是 k,所以可以枚举 k 来算

考虑这个转移,可以理解成 0 -> n,每次走 k 步或 1 步,即 n=ak+b,贡献分别为 n 、(1 - n)
用组合数可以表示成

a=0nk(a+naka)(1n)annak

答案就是 ni=1i(f[n][i+1]f[n][i])=nn+1ni=1f[n][i]

但注意一点,当 n == k 的时候,其实前面没有限制,所以答案会有 1 的差,所以要减掉 QAQ

求 n、(1 - n) 的次方可以预处理,不然复杂度还会加个 log …(好吧,只有我会写错QAQ

复杂度 O(NlogN)

【答案】97138867

#include<iostream>#include<cstdlib>#include<cstdio>#include<string>#include<cstring>#include<ctime>//#include<cmath>#include<algorithm>#define M 1000000009#define N 7500000#define LL long longusing namespace std;LL n = N,ans;LL frac[N + 5],inv[N + 5],pow[N + 5],pow1[N + 5];LL ksm(LL a,LL b){    LL ret = 1;    for (;b;b >>= 1,a = a * a % M)        if (b & 1) ret = ret * a % M;    return ret;}LL C(int n,int m){    if (!m || n == m) return 1;    return frac[n] * inv[m] % M * inv[n - m] % M;}LL cal(int m,int k){    LL ret = 0;    for (int a = 0;a * k <= m;a ++)        (ret += C(a + m - a * k,a) * pow1[a] % M * pow[m - a * k]) %= M;    return ret;}int main(){    frac[0] = pow1[0] = pow[0] = 1;    for (int i = 1;i <= n;i ++)    {        frac[i] = frac[i - 1] * i % M;        pow[i] = pow[i - 1] * n % M;        pow1[i] = pow1[i - 1] * (1ll - n) % M;    }    inv[n] = ksm(frac[n],M - 2);    for (int i = n;i;i --) inv[i - 1] = inv[i] * i % M;    for (int k = 2;k <= n;k ++)        (ans += (cal(n - 1,k) - cal(n - k,k)) * n) %= M;    ans = (ksm(n,n + 1) - ans) % M;    if (ans < 0) ans += M;    cout << ans << endl;    return 0;}
0 0