noi.acNOIP模擬賽5-count
阿新 • • 發佈:2018-09-24
main bin 有一個 urn ret string 長度 freopen fft ?
題面鏈接
戳我
題意簡述
你有一個n+1個數的序列,都是1~n,其中只有一個有重復,求每個長度的本質不同的子序列個數。\(mod 1e9+7\)。
sol
說起來也很簡單,設相同的數出現的位置為\(l\)和\(r\)。那麽除了去掉\(r\)之後\(n\)個數的貢獻,還有算上\(r\)的貢獻,然後就可以了。原本\(n\)個的貢獻是\(\binom{n}{i}\),加上\(r\)的貢獻的話要滿足在\([l,r-1]\)之間至少要選一個數,然後還要選\(r\),那麽考慮將原序列(去除\(r\))分成三段,\([1,l-1],[l,r-1],[r+1,n+1]\),可以枚舉長度,發現是一個卷積,於是可以愉快的NTT辣,然後模數是\(1e9+7\)
md不管蒯一個三模數NTT暴力艹過去。總復雜度 $ O(nlogn) $ 。其實好像有 $ O(n) $ 做法,但我懶得想。
#include<cstdio> #include<cstring> #include<algorithm> #define gt getchar() #define ll long long #define maxn 400005 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) #define Set(a) memset(a,0,sizeof a) using std::swap; using std::reverse; inline int in() { int k=0;char ch=gt; while(ch<'-')ch=gt; while(ch>'-')k=k*10+ch-'0',ch=gt; return k; } int pr[]={469762049,998244353,1004535809}; const int md=1e9+7,YL=md; inline ll ksm(ll a,ll b,ll p) { ll r=1;a%=p; while(b){if(b&1)r=r*a%p;a=a*a%p,b>>=1;} return r; } int R[maxn]; struct FFT { int G,P,A[maxn]; void NTT(int* a,int n,int f) { for (int i=0;i<n;i++)if(i<R[i])swap(a[i],a[R[i]]); for (int i=1;i<n;i<<=1) { int gn=ksm(G,(P-1)/(i<<1),P); for(int j=0;j<n;j+=(i<<1)) { int g=1,x,y; for (int k=0;k<i;k++,g=1ll*g*gn%P) { x=a[j+k],y=1ll*g*a[j+k+i]%P; a[j+k]=(x+y)%P,a[j+k+i]=(x+P-y)%P; } } } if(f==1)return; int nv=ksm(n,P-2,P);reverse(a+1,a+n); for(int i=0;i<n;i++)a[i]=1ll*a[i]*nv%P; } }fft[3]; int F[maxn],G[maxn],B[maxn],deg1,deg2,deg; ll ans[maxn]; ll inv(ll n,ll p){return ksm(n % p,p - 2,p);} ll mul(ll a,ll b,ll p) { ll re=0; for(;b;b>>=1,a=(a+a)%p) if(b&1)re=(re+a)%p; return re; } void CRT() { deg=deg1+deg2; ll a,b,c,t,k,M=1ll*pr[0]*pr[1]; ll inv1=inv(pr[1],pr[0]),inv0=inv(pr[0],pr[1]),inv3=inv(M%pr[2],pr[2]); for(int i=0;i<=deg;i++) { a=fft[0].A[i],b=fft[1].A[i],c=fft[2].A[i]; t=(mul(a*pr[1]%M,inv1,M)+mul(b*pr[0]%M,inv0,M))%M; k=((c-t%pr[2])%pr[2]+pr[2])%pr[2]*inv3%pr[2]; ans[i]=((k%md)*(M%md)%md+t%md)%md; } } void pre() { int n=1,L=0; while(n<=(deg1+deg2))n<<=1,L++; for (int i=1;i<n;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(L-1)); for (int u=0;u<=2;u++) { fft[u].G=3;fft[u].P=pr[u]; for(int i=0;i<=deg1;i++)fft[u].A[i]=F[i]; for(int i=0;i<=deg2;i++)B[i]=G[i]; for(int i=deg2+1;i<n;i++)B[i]=0; fft[u].NTT(fft[u].A,n,1);fft[u].NTT(B,n,1); for(int i=0;i<n;i++)fft[u].A[i]=1ll*fft[u].A[i]*B[i]%pr[u]; fft[u].NTT(fft[u].A,n,-1); } } void get_mul(int *a,int *b,int *c,int n,int m) { deg1=n;deg2=m; for(int i=0;i<=deg1;++i)F[i]=a[i]; for(int i=0;i<=deg2;++i)G[i]=b[i]; pre();CRT(); for(int i=0;i<=deg;++i)c[i]=ans[i]; } const int N=1e6+7; inline int ksm(int a,int k){int r=1;while(k){if(k&1)r=1ll*a*r%YL;a=1ll*a*a%YL,k>>=1;}return r;} int fac[N],fnv[N],ma[N],as[N]; inline int C(int x,int y){return y>x?0:1ll*fac[x]*fnv[y]%YL*fnv[x-y]%YL;} inline int MO(const int &a){return a>=YL?a-YL:a;} int a[N],b[N],c[N]; int main() { // File("conut"); int n=in();fac[0]=fnv[0]=1; for(int i=1;i<=n+1;++i)fac[i]=1ll*fac[i-1]*i%YL; fnv[n+1]=ksm(fac[n+1],YL-2); for(int i=n;i;--i)fnv[i]=1ll*fnv[i+1]*(i+1)%YL; int l=1,r=n+1; for(int i=1,u;i<=n+1;++i) { u=in(); if(ma[u])l=ma[u],r=i; ma[u]=i; } for(int i=1;i<=n;++i)as[i]=C(n,i); int l1=l-1,l2=r-l,l3=n-r+1; for(int i=0;i<=l1;++i)a[i]=C(l1,i); for(int i=1;i<=l2;++i)b[i]=C(l2,i); get_mul(a,b,b,l1,l2); Set(a),Set(ans),Set(F),Set(G),Set(fft); for(int i=0;i<=l3;++i)a[i]=C(l3,i); get_mul(a,b,b,l3,l1+l2); for(int i=1;i<=n;++i)as[i+1]=MO(as[i+1]+b[i]); for(int i=1;i<=n+1;++i)printf("%d\n",as[i]); return 0; }
noi.acNOIP模擬賽5-count