题目大意
给定一个数$n$,构造一个无限长的序列$A$,使得
$\forall i,j\geq n,A_i=A_j$
$\forall i<j<k\leq i+a_i,A_j=A_k$
求构造总方案数,$n\leq 10^6$,答案对$10^9+7$取模。
题解
易证对于$i<n$若$\exists A_i>1,A_{i+1}>1$,那么一定$\forall j>i+1,a_j=a_i$。
设$DP$状态$F_i$表示第$a_i=1$且$\forall j<i,j+A_j\leq i$的方案数。
考虑第$i$位作为一个$j<i,A_j+j=i,A_j>1$的结尾,那么有$F_i+=\sum\limits_{j=0}^{i-3}F_j$
否则$F_i+=F_{i-1}$。
枚举结尾是$A_n,A_{n-1}>1$或$\exists A_j>1,A_n=1,A_j+j>n$或$\max\{A_j+j\}\leq n$。
对于第一种情况,直接枚举最后一个$1$出现的位置$i$对答案的贡献为$F_i\times (n-1)^2$
对于第二种情况,枚举$j$出现的位置(显然只会出现一个),一定有$A_{j-1}=1$,对答案的贡献为$F_{j-1}\times (j-[j<n])$,因为要满足$j+A_j+1>n,A_j>1$。
对于第三种情况,对答案的贡献直接就是$F_n$。
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define M 2000200 #define mod 1000000007 using namespace std; namespace IO{ int Top=0;char SS[20]; void write(int x){ if(!x){putchar('0');return;} if(x<0) x=-x,putchar('-'); while(x) SS[++Top]=x%10,x/=10; while(Top) putchar(SS[Top]+'0'),--Top; } int read(){ int nm=0; char cw=getchar(); for(;!isdigit(cw);cw=getchar()); for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0'); return nm; } }using namespace IO; int add(int x,int y){return (x+y>=mod)?x+y-mod:x+y;} int mul(int x,int y){return (LL)x*(LL)y%mod;} void upd(int &x,int y){x=add(x,y);} int n,m,F[M],S[M],ans; int main(){ n=read(),F[0]=S[0]=1; for(int i=1;i<=n;i++) F[i]=i>2?S[i-3]:0,upd(F[i],F[i-1]),S[i]=add(S[i-1],F[i]); for(int i=0;i<n;i++) upd(ans,mul(F[i],i+(i<n-1))); for(int i=0;i<n-1;i++) upd(ans,mul(F[i],mul(n-1,n-1))); upd(ans,F[n]),write(ans),putchar('\n');return 0; }