题意
让你构造一个每个数为1~n的无限长的序列,满足:
-
第n个数与它后面的数都相同
-
对于每一个数x,它和后面的x个数都相同。
问你有多少种方案。
题解
考虑dp,设 f [ i ] f[i] f[i]代表第i~n位都填好的方案数,倒着dp。
转移分3种情况:
当第i位是1时, f [ i ] + = f [ i + 1 ] f[i]+=f[i+1] f[i]+=f[i+1]。
当第i位不是1并且第i+1位也不是1时,这个序列就只能长成 x y y y y y y y y y y y y . . . xyyyyyyyyyyyy... xyyyyyyyyyyyy...的样子了,其中 x x x和 y y y可以填任意非1数,所以 f [ i ] + = ( n − 1 ) ∗ ( n − 1 ) f[i]+=(n-1)*(n-1) f[i]+=(n−1)∗(n−1).
当第i位不是1但是第i+1位是1时,这个序列就长成 x 11111 S x11111S x11111S的样子了,所以对于每一个 x x x, f [ i ] + = f [ i + x + 1 ] f[i]+=f[i+x+1] f[i]+=f[i+x+1](如果 i + x + 1 > n i+x+1>n i+x+1>n那么 f [ i + x + 1 ] = 1 f[i+x+1]=1 f[i+x+1]=1),维护一个 f f f的后缀和就可以做到 O ( 1 ) O(1) O(1)转移了。
时间复杂度: O ( n ) O(n) O(n)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define MAXN 1000010
#define mod 1000000007
int n,f[MAXN],add;
int main()
{
scanf("%d",&n);
f[n]=n;
f[n-1]=(long long)n*n%mod;
for(int i=n-2;i>=1;--i)
{
add=(add+f[i+3])%mod;
f[i]=f[i+1];
f[i]=(f[i]+(long long)(n-1)*(n-1)%mod)%mod;
f[i]=(f[i]+add)%mod;
f[i]=(f[i]+i+1)%mod;
}
printf("%d\n",f[1]);
}