SDOI2015序列统计

Posted shxnb666

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDOI2015序列统计相关的知识,希望对你有一定的参考价值。

题面

https://www.luogu.org/problem/P3321

题解

首先贡献是$f[a_ib_i]+=f1[a_i]\times f2[b_i]$,用原根变成$f[a_i+b_i]+=f1[a_i]\times f2[b_i]$,即形成一个新的映射。

开个桶,即求这个多项式的$n$次幂。

$NTT+$分治快速幂。

自己编的$NTT$口诀:

上倍增,中加二倍,下加加。

上界$1,0,0$,下界$li,li,mi$

原根$3$,$2^mid$次单位根$w0=phi(p)/2mid$($FFT$:$w0=\cos(pi/mid),sin(pi/mid)\times opt\$)

加($mid$)乘($w$),加($mid$)减($y$)。

$-1$时,$reverse(1,lim)$除以$lim$

#include<cmath>
#include<stack>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ri register int
#define N 100000
#define mod 1004535809
#define LL long long

using namespace std;

inline int read() 
  int ret=0; char ch=getchar();
  while (ch<0 || ch>9) ch=getchar();
  while (ch>=0 && ch<=9) ret*=10,ret+=(ch-0),ch=getchar();
  return ret;


int n,m,x,t;
int f[N],s[N];
int a[N],mp[N],b[N],ftr[30];
int lim=1,l=0,r[N],ret[N];

int pow(int a,int b,int p) 
  int ret=1;
  for (;b;b>>=1,a=a*1LL*a%p) if (b&1) ret=ret*1LL*a%p;
  return ret;


int getg(int m) 
  int tmp=m-1;
  int c=0;
  for (ri i=2;i*i<=tmp;i++) if (tmp%i==0) 
    ftr[++c]=i;
    while (tmp%i==0) tmp/=i;
  
  if (tmp>1) ftr[++c]=tmp;
  for (ri g=2;g<=m-1;g++) 
    bool fl=0;
    for (ri j=1;j<=c;j++) if (pow(g,(m-1)/ftr[j],m)==1) fl=1;break;
    if (!fl) return g;
  
  return -1;


void NTT(int *p,int opt) 
  for (ri i=0;i<lim;i++) if (i<r[i]) swap(p[i],p[r[i]]);
  for (ri i=1;i<lim;i<<=1) 
    int w0=pow(3,(mod-1)/(i<<1),mod);
    for (ri j=0;j<lim;j+=2*i) 
      int w=1;
      for (ri k=0;k<i;k++,w=w*1LL*w0%mod) 
        int x=p[j+k],y=p[i+j+k]*1LL*w%mod;
        p[j+k]=(x+y)%mod; p[i+j+k]=(x-y+mod)%mod;
      
    
  
  if (opt==-1) 
    reverse(&p[1],&p[lim]);
    int inv=pow(lim,mod-2,mod);
    for (ri i=0;i<lim;i++) p[i]=p[i]*1LL*inv%mod;
  


void mul(int *a1,int *a2,int *c) 
  memset(a,0,sizeof(a)); memset(b,0,sizeof(b));
  for (ri i=0;i<m-1;i++) a[i]=a1[i],b[i]=a2[i];
  NTT(a,1); NTT(b,1);
  for (ri i=0;i<lim;i++) a[i]=a[i]*1LL*b[i]%mod;
  NTT(a,-1);
  memset(ret,0,sizeof(ret));
  for (ri i=0;i<m-1;i++) ret[i]=(a[i]+a[i+m-1])%mod;
  for (ri i=0;i<m-1;i++) c[i]=ret[i];


int main() 
  n=read(); m=read(); x=read(); t=read();
  int g=getg(m);
  for (ri i=0;i<m-1;i++) mp[pow(g,i,m)]=i;
  while (lim<=2*(m-2)) lim<<=1,l++;
  for (ri i=0;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
  for (ri i=1;i<=t;i++) 
    int xx=read()%m;
    if (xx) f[mp[xx]]++;
  
  s[mp[1]]=1;
  for (;n;n>>=1,mul(f,f,f)) if (n&1) mul(s,f,s);
  printf("%d\n",s[mp[x]]);

 

以上是关于SDOI2015序列统计的主要内容,如果未能解决你的问题,请参考以下文章

P3321 [SDOI2015]序列统计(未解决)

BZOJ 3992: [SDOI2015]序列统计

[SDOI2015]序列统计

bzoj3992SDOI2015序列统计

[BZOJ3992][SDOI2015]序列统计

[SDOI2015]序列统计