zoukankan      html  css  js  c++  java
  • 【题解】SDOI2015序列统计

    【题解】SDOI2015序列统计

    来自永不AFO的YYB的推荐

    这里是乘积,比较麻烦,不过由于给定的序列膜数是个小质数,所以可以(O(m^2log m))找原跟(实际上不需要这么多)。

    乘积有点麻烦,转换成加法就好了,然后取离散对数(a_iequiv g^{c_i} mod m),现在每个元素都用原根的指数代替了,问题就转变成了有多少种方案使得每个元素的乘积等于(log xmod m)

    根据题意直接构造

    [F(x)=sum [exist log a_i=i]x^i ]

    答案就是

    [F(x)^n ]

    吗?

    其实要魔改一下,乘的过程中要不断地让(F(x))大于(x^m)的系数算到(x^{i mod m})上,原因显然,略。

    不能这么敷衍,到时候自己看会一头雾水,取膜的原因是,我们利用的是多项式乘法的组合意义,现在组合意义是要得到(c_i=sum_limits{k+j equiv i mod m}a_kb_j),所以如此。

    既然要不断地让(F(x))(x^m)取膜,所以(ln ,exp)废了

    直接写两个(log)快速幂跑得飞快

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    
    using namespace std;  typedef long long ll;
    inline int qr(){
          register int ret=0,f=0;
          register char c=getchar();
          while(c<48||c>57)f|=c==45,c=getchar();
          while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
          return f?-ret:ret;
    }
    
     
    
    int n,m,x,s,g;
    vector < int > ve;
    const int maxn=8009;
    int lg[maxn];
    int read[1<<19|1];
    int ans[1<<19|1];
    
    
    namespace poly{
          const int maxn=1<<19|1;
          int a[maxn],b[maxn],r[maxn];
          int savlen;
          inline void getr(const int&len){
    	    if(len==savlen)return;
    	    int cnt=0;
    	    for(register int t=1;t<len;t<<=1)++cnt;
    	    for(register int t=1;t<len;++t)
    		  r[t]=r[t>>1]>>1|(t&1)<<cnt>>1;
          }
          const int mod=1004535809;
          const int g=3;
          inline int ksm(int base,ll p){
    	    register int ret=1;
    	    for(base%=mod;p;p>>=1,base=1ll*base*base%mod)
    		  if(p&1) ret=1ll*ret*base%mod;
    	    return ret;
          }
          const int gi=ksm(3,mod-2);
          
          
          inline void NTT(int*a,const int&len,const int&tag){
    	    getr(len);
    	    for(register int t=1;t<len;++t)
    		  if(r[t]>t) swap(a[t],a[r[t]]);
    	    int *a1,*a0,s=g;
    	    if(tag!=1) s=gi;
    	    for(register int t=1,wn;t<len;t<<=1){
    		  wn=ksm(s,(mod-1)/(t<<1));
    		  for(register int i=0;i<len;i+=t<<1){
    			a1=(a0=a+i)+t;
    			for(register int j=0,w=1,tm;j<t;++j,++a1,++a0,w=1ll*w*wn%mod){
    			      tm=1ll**a1*w%mod;
    			      *a1=(*a0-tm)%mod;
    			      *a0=(*a0+tm)%mod;
    			      if(*a1<0)*a1+=mod;
    			}
    		  }
    	    }
    	    if(tag!=1)
    		  for(register int t=0,in=ksm(len,mod-2);t<len;++t)
    			a[t]=1ll*a[t]*in%mod;
          }
          
          
          inline void print(int*a,int len){
    	    for(register int t=0;t<len;++t)
    		  printf("%d ",a[t]);
    	    putchar('
    ');
          }
    
    
          inline void KSM(int*a,int*b,const int&len,int p){
    	    static int ret[maxn],base[maxn];
    	    memset(ret,0,sizeof ret);
    	    memset(base,0,sizeof base);
    	    ret[0]=1;
    	    for(register int t=0;t<len;++t) base[t]=a[t];
    	    while(p){
    		  NTT(base,len<<1,1);
    		  if(p&1){
    			NTT(ret,len<<1,1);
    			for(register int t=0;t<len<<1;++t) ret[t]=1ll*ret[t]*base[t]%mod;
    			NTT(ret,len<<1,-1);
    			for(register int t=(len<<1)-1;t-m+1>=0;--t) ret[t-m+1]=(ret[t-m+1]+ret[t])%mod,ret[t]=0;
    		  }
    		  for(register int t=0;t<len<<1;++t) base[t]=1ll*base[t]*base[t]%mod;
    		  NTT(base,len<<1,-1);
    		  for(register int t=(len<<1)-1;t-m+1>=0;--t) base[t-m+1]=(base[t-m+1]+base[t])%mod,base[t]=0;
    		  p>>=1;
    	    }
    	    for(int t=0;t<len;++t) b[t]=ret[t];
          }      
    }
    
    
    inline int ksm(const int&base,const int&p,const int&mod=m){
          register int ret=1;
          for(register int t=p,b=base%mod;t;t>>=1,b=1ll*b*b%mod)
    	    if(t&1) ret=1ll*ret*b%mod;
          return ret;
    }
    
    inline void findg(){
    #define mod m
          int k=m-1;
          for(register int t=2;1ll*t*t<=k;++t){
    	    if(k%t==0){
    		  ve.push_back(t);
    		  if(k/t!=t) ve.push_back(k/t);
    	    }
          }
          //for(auto f:ve) cout<<"fac="<<f<<endl;
          for(register int t=2;;++t){
    	    int l=1;
    	    for(auto f:ve)
    		  if(ksm(t,f)==1) l=0;
    	    if(l) {g=t;return;}
          }
          
    #undef mod
    }
    
    
    int main(){
    
          freopen("sdoi2015_sequence.in","r",stdin);
          freopen("sdoi2015_sequence.out","w",stdout);
          
          n=qr();m=qr();x=qr();s=qr();
          findg();
          
          for(register int t=1,k=g;t<m-1;++t,k=1ll*k*g%m) lg[k]=t;
          for(register int t=1;t<=s;++t) {int t1=qr();if(t1)read[lg[t1]]=1;}
          
          int k=1;
          while(k<=m) k<<=1;
          poly::KSM(read,read,k,n);
          //for(register int t=0;t<k;++t) cout<<read[t]<<' ';
          //cout<<endl;
          int ans=read[lg[x]];
          printf("%d
    ",ans);
          return 0;
    }
    
    
  • 相关阅读:
    2020-2021-1 20201314 《信息安全专业导论》第七周学习总结
    2020-2021-1 20201314 《信息安全导论》第六周学习总结
    fibnacci数列递归实现
    实现进制转化伪代码
    求最大公约数伪代码
    2020-2021-1 20201314 《信息安全专业导论》第五周学习总结
    xor 加密
    Pep9 课下作业
    2020-2021-1 20201314 《信息安全专业导论》第四周学习总结
    寻找你的黑客偶像
  • 原文地址:https://www.cnblogs.com/winlere/p/11260689.html
Copyright © 2011-2022 走看看