题目大意
给定一个数$n$,构造一个无限长的序列$A$,使得
$forall i,jgeq n,A_i=A_j$
$forall i<j<kleq i+a_i,A_j=A_k$
求构造总方案数,$nleq 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_jleq i$的方案数。
考虑第$i$位作为一个$j<i,A_j+j=i,A_j>1$的结尾,那么有$F_i+=sumlimits_{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 imes (n-1)^2$
对于第二种情况,枚举$j$出现的位置(显然只会出现一个),一定有$A_{j-1}=1$,对答案的贡献为$F_{j-1} imes (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('
');return 0;
}