BZOJ 3992 [SDOI2015]序列统计
生活随笔
收集整理的這篇文章主要介紹了
BZOJ 3992 [SDOI2015]序列统计
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
數列長度到了109,轉移矩陣邊長n到了8000,除了FFT還能怎么寫??!!
當然,這題由于取模,必須用NTT.
同時由于取得是乘積,所以用m的原根來搞,每次NTT完了,把后面的部分加到前面去.
注意,X不會出現0,因此一旦S集合中出現0,刪掉.原根判不了0.
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<string> #include<cmath> #include<ctime> #include<algorithm> #include<map> #include<set> #include<queue> #include<iomanip> using namespace std; #define ll long long #define db double #define up(i,j,n) for(ll i=j;i<=n;i++) #define pii pair<ll,ll> #define uint unsigned ll #define FILE "dealing" ll read(){ll x=0,f=1,ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f; } template<class T> bool cmax(T& a,T b){return a<b?a=b,true:false;} template<class T> bool cmin(T& a,T b){return a>b?a=b,true:false;} const ll maxn=400100,limit=128,inf=1000000000,r=3,mod=1004535809; ll n,m,X,S,G; ll a[maxn],b[maxn],id[maxn]; ll fast(ll a,ll b,ll mod){ll ans=1;while(b){if(b&1)ans=ans*a%mod;b>>=1;a=a*a%mod;}return ans; } void print(ll* a,ll len){up(i,0,len-1)printf("%lld ",a[i]);cout<<endl; } namespace prepare{//求M原根const ll maxn=8080;ll b[maxn],prime[maxn],tail,q[maxn],head;void getprime(){for(ll i=2;i<maxn;i++){if(!b[i])prime[++tail]=i;for(ll j=1;prime[j]*i<maxn&&j<=tail;j++){b[i*prime[j]]=1;if(i%prime[j]==0)break;}}}ll solve(ll N){getprime();ll p=N-1;N--;for(ll i=1;i<=tail;i++){if(N==1)break;if(N%prime[i]==0)q[++head]=prime[i];while(N%prime[i]==0)N/=prime[i];}for(ll i=2;i<=p;i++){bool flag=0;for(ll j=1;j<=head;j++)if(fast(i,p/(q[j]),p+1)==1)flag=1;if(!flag)return i;}return 0;} }; namespace NTT{ll R[maxn],a[maxn],b[maxn],w[maxn];ll H,L;void NTT(ll* a,ll flag){for(ll i=0;i<L;i++)if(i<R[i])swap(a[i],a[R[i]]);for(ll len=2;len<=L;len<<=1){ll g=fast(r,(mod-1)/len,mod),l=len>>1;if(flag)g=fast(g,mod-2,mod);w[0]=1;up(i,1,l)w[i]=w[i-1]*g%mod;for(ll st=0;st<L;st+=len)for(ll k=0;k<l;k++){ll x=a[st+k],y=w[k]*a[st+k+l]%mod;a[st+k]=(x+y)%mod,a[st+k+l]=(x-y+mod)%mod;}}if(flag){ll inv=fast(L,mod-2,mod);up(i,0,L-1)a[i]=a[i]*inv%mod;}}void solve(ll* c,ll* d,ll n,ll m,ll* ch){n++,m++;up(i,0,n-1)a[i]=c[i];up(i,0,m-1)b[i]=d[i];for(H=0,L=1;L<n+m-1;H++)L<<=1;up(i,n,L)a[i]=0;up(i,m,L)b[i]=0;up(i,1,L)R[i]=(R[i>>1]>>1)|((i&1)<<(H-1));NTT(a,0);NTT(b,0);up(i,0,L-1)a[i]=a[i]*b[i]%mod;NTT(a,1);up(i,0,n+m-2)ch[i]=a[i];} }; ll c[maxn],ans[maxn],tmp[maxn]; int main(){freopen(FILE".in","r",stdin);freopen(FILE".out","w",stdout);n=read();m=read();X=read(),S=read();up(i,1,S)a[i]=read();G=prepare::solve(m);ll w=1;up(i,0,m-1){id[w]=i;w=w*G%m;}up(i,1,S)if(a[i])a[i]=id[a[i]];X=id[X];up(i,1,S)if(a[i])c[a[i]]++;ans[0]=1;while(n){if(n&1){NTT::solve(ans,c,m,m,tmp);up(i,0,m-1)ans[i]=tmp[i];up(i,1,m)ans[i]=(ans[i]+tmp[i+m-1])%mod;}n>>=1;NTT::solve(c,c,m,m,tmp);up(i,0,m-1)c[i]=tmp[i];up(i,1,m)c[i]=(c[i]+tmp[i+m-1])%mod;}printf("%lld\n",ans[X]);return 0; }
轉載于:https://www.cnblogs.com/chadinblog/p/6556004.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的BZOJ 3992 [SDOI2015]序列统计的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS项目之同时点击多个按钮解决方案
- 下一篇: BZOJ 3910 并查集+线段树合并