[扩展欧拉定理] BZOJ 4869 [Shoi2017]相逢是问候

来源:互联网 发布:久久网络 编辑:程序博客网 时间:2024/05/17 05:09

欧拉定理 aϕ(n)1(modn),(a,n)=1
进而有 ababmodϕ(n)(modn),(a,n)=1
那么对于an不互质 我们有扩展欧拉定理
ababmodϕ(n)+ϕ(n)(modn),(a,n)1bϕ(n)
注意 b<ϕ(n)的时候是不成立的 比如 22mod822+4mod8

然后这题类似 BZOJ3884: 上帝与集合的正确用法
只要取O(logp)层phi 就会模1
因为要注意 bϕ 的大小关系 我在省选前写的懵懵懂懂 昨天才发现这个trick 去学习了很多人的很多写法
裸的写是O(nlog3p) 发现有一个log是快速幂
可以用这里提到的技巧 类似分块的预处理出幂 然后可以O(1)
那么就是O(nlog2p)

#include<cstdio>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;typedef long double ld;inline char nc(){  static char buf[100000],*p1=buf,*p2=buf;  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline void read(int &x){  char c=nc(),b=1;  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;}inline int Phi(int n){  int t=n,tmp=n;  for (int j=2;(ll)j*j<=tmp;j++)    if (t%j==0){      n=n/j*(j-1);      while (t%j==0) t/=j;    }  if (t>1) n=n/t*(t-1);  return n;}const int N=50005;const int _K=30;int n,m,K;int a[N],_a[N],pt[N];int p[_K],P,C;int fat[N];inline int Fat(int u){ return fat[u]==u?u:fat[u]=Fat(fat[u]); }int c[N];inline void add(int x,int r){ for (int i=x;i<=n;i+=i&-i) (c[i]+=r)%=P; }inline int sum(int x){ int ret=0; for (int i=x;i;i-=i&-i) (ret+=c[i])%=P; return ret; }/*bool bo;inline int Pow(ll a,int b,int p){  int ret=1; bo=0;  for (;b;a=a*a%p,b>>=1){    if (b&1)      bo|=(a*ret>=p),ret=ret*a%p;    bo|=a*a>=p;  }  return ret;}inline int modify(int i,int L){  int ret=_a[i]%p[L]; bo=_a[i]>=p[L];  for (int k=L;k;k--)    ret=Pow(C,ret+(bo?p[k]:0),p[k-1]);  return ret;  }*/ll pw[_K][N],pw1[_K][N],pw2[N],pw3[N];inline int modify(int i,int L){  int ret=_a[i],z=_a[i];  while (L--){    if (z<P)      ret=pw1[L][z>>14]*pw[L][z&16383]%p[L];    else      ret=pw1[L][ret+p[L+1]>>14]*pw[L][ret+p[L+1]&16383]%p[L];    z=pw3[z>>14]*pw2[z&16383]>P?P:pw3[z>>14]*pw2[z&16383];  }  return ret;}int main(){  freopen("t.in","r",stdin);  freopen("t.out","w",stdout);  read(n); read(m); read(P); read(C);  for (int i=1;i<=n;i++) read(a[i]),_a[i]=a[i];  p[K=0]=P; int tt=P;  while (tt>1) p[++K]=Phi(tt),tt=p[K];  p[++K]=1;  for(int i=0;i<K;i++){    for(int j=*pw[i]=1;j<=16384;j++) pw[i][j]=pw[i][j-1]*C%p[i];    for(int j=*pw1[i]=1;j<16384;j++) pw1[i][j]=pw1[i][j-1]*pw[i][16384]%p[i];  }  for(int j=*pw2=1;j<=16384;j++) pw2[j]=pw2[j-1]*C>P?P:pw2[j-1]*C;  for(int j=*pw3=1;j<16384;j++) pw3[j]=pw3[j-1]*pw2[16384]>P?P:pw3[j-1]*pw2[16384];  int order,l,r;  for (int i=1;i<=n+1;i++) fat[i]=i,add(i,a[i]);  while (m--){    read(order); read(l); read(r);    if (order==0){      for (int i=Fat(l);i<=r;i=Fat(i+1)){    add(i,P-a[i]);    a[i]=modify(i,++pt[i]);    add(i,a[i]);    if (pt[i]==K) fat[i]=i+1;      }    }else      printf("%d\n",(sum(r)+P-sum(l-1))%P);  }  return 0;}
0 0
原创粉丝点击