Arc071_F Infinite Sequence

传送门

题目大意

给定一个数$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;
}
原文地址:https://www.cnblogs.com/OYJason/p/9843254.html