题目大意:设 S 为长度为 n,元素大小为 1 到 n 的整数的排列集合,L(X) 为排列 X 中连续值相同的最长长度,求 ∑X|SL(S),其中 n=7500000
设 F[n][k] 表示长度为 n 的序列,L < k 的方案数
易得递推式
F[n][k]=F[n−1][k]∗n−F[n−k][k]∗(n−1)
第二维都是 k,所以可以枚举 k 来算
考虑这个转移,可以理解成 0 -> n,每次走 k 步或 1 步,即 n=ak+b,贡献分别为 n 、(1 - n)
用组合数可以表示成
∑a=0⌊nk⌋(a+n−aka)(1−n)ann−ak
答案就是 ∑ni=1i(f[n][i+1]−f[n][i])=nn+1−∑ni=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 long
using 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;
}