bzoj3283: 运算器

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cmath>
  5 #include <algorithm>
  6 using namespace std;
  7 typedef long long int64;
  8 int Case;
  9 #define maxn 200005
 10 #define maxm 600005
 11 int now[maxn],prep[maxm];
 12 int64 val[maxm],pi,pk,t;
 13 int64 ksm(int64 x,int64 y,int64 p){
 14     if (y==0) return 1%p;
 15     if (y==1) return x%p;
 16     int64 d=ksm(x,y/2,p);
 17     if (y%2==1) return d*d%p*x%p;
 18     else return d*d%p;
 19 }
 20 int64 exgcd(int64 a,int64 b,int64 &x,int64 &y){
 21     if (b==0){
 22         x=1,y=0;
 23         return a;
 24     }
 25     int64 GCD=exgcd(b,a%b,x,y),temp;
 26     temp=x,x=y,y=temp-a/b*y;
 27     return GCD;
 28 }
 29 void insert(int x,int64 y){
 30     int pos=y%maxn;
 31     prep[x]=now[pos],now[pos]=x,val[x]=y;
 32 }
 33 int search(int64 x){
 34     int pos=x%maxn,ans=maxm*4;
 35     for (int i=now[pos];i!=-1;i=prep[i]){
 36         if (val[i]==x) ans=min(ans,i);
 37     }
 38     if (ans<maxm*4) return ans;
 39     else return -1;
 40 }
 41 int64 extanded_baby_step_gaint_step(int64 A,int64 B,int64 C){
 42     int64 tmp,temp=1,x,y,D,R,cnt=0; int pos;
 43     for (int i=0;i<32;i++){
 44         if (temp==B) return i;
 45         temp=temp*A%C;
 46     }
 47     D=1;
 48     for (temp=exgcd(A,C,x,y);temp!=1;cnt++,temp=exgcd(A,C,x,y)){
 49         if (B%temp) return -1;
 50         C/=temp,B/=temp;
 51         D=D*(A/temp)%C;
 52     }
 53     memset(now,-1,sizeof(now));
 54     R=1; tmp=ceil(sqrt(C*1.0));
 55     for (int i=0;i<tmp;i++){
 56         insert(i,R);
 57         R=R*A%C;
 58     }
 59     for (int i=0;i<tmp;i++){
 60         temp=exgcd(D,C,x,y);
 61         x=(x%C*(B/temp)%C+C)%C;
 62         pos=search(x);
 63         if (pos!=-1) return i*tmp+pos+cnt;
 64         D=D*R%C;
 65     }
 66     return -1;
 67 }
 68 int64 inv(int64 X){
 69     int64 x,y;
 70     int64 temp=exgcd(X,pk,x,y);
 71     return (x%pk+pk)%pk;
 72 }
 73 int64 work(int64 n){
 74     if (n==0) return 1LL%pk;
 75     int64 ans=1;
 76     for (int i=1;i<=pk;i++) if (i%pi) ans=ans*i%pk;
 77     ans=ksm(ans,n/pk,pk);
 78     int64 k=n%pk;
 79     for (int i=1;i<=k;i++) if (i%pi) ans=ans*i%pk;
 80     return ans*work(n/pi)%pk;
 81 }
 82 int64 calc(int64 n,int64 m){
 83     int64 a,b,c; int64 k=0;
 84     a=work(n),b=work(n-m),c=work(m);
 85     for (int i=n;i;i/=pi) k+=(i/pi);
 86     for (int i=n-m;i;i/=pi) k-=(i/pi);
 87     for (int i=m;i;i/=pi) k-=(i/pi);
 88     return 1LL*ksm(pi,k,pk)%pk*a%pk*inv(b)%pk*inv(c)%pk;
 89 }
 90 void work1(){
 91     int64 n,m,p;
 92     scanf("%lld%lld%lld",&n,&m,&p);
 93     printf("%lld\n",ksm(n,m,p)%p);
 94 }
 95 void work2(){
 96     int64 A,B,C,ans;
 97     scanf("%lld%lld%lld",&A,&B,&C);
 98     B%=C;
 99     ans=extanded_baby_step_gaint_step(A,B,C);
100     if (ans==-1) printf("Math Error\n");
101     else printf("%lld\n",ans);
102 }
103 void work3(){
104     int64 n,m,p,temp,x,y,tmp,ans=0;
105     scanf("%lld%lld%lld",&m,&n,&p);
106     t=p;
107     for (int i=2;i<=sqrt(p);i++){
108         if (t%i==0){
109             pi=i,pk=1;
110             while (t%i==0){
111                 pk=pk*i;
112                 t/=i;
113             }
114             temp=exgcd(p/pk,pk,x,y);
115             tmp=calc(n,m)/temp;
116             x=x*tmp%p*(p/pk)%p;
117             ans=(ans+x)%p;
118         }
119     }
120     if (t>1){
121         pi=t,pk=t;
122         temp=exgcd(p/pk,pk,x,y);
123         tmp=calc(n,m)/temp;
124         x=x*tmp%p*(p/pk)%p;
125         ans=(ans+x)%p;
126     }
127     printf("%lld\n",(ans%p+p)%p);
128 }
129 int main(){
130     scanf("%d",&Case);
131     for (int type;Case;Case--){
132         scanf("%d",&type);
133         if (type==1) work1();
134         else if (type==2) work2();
135         else work3();
136     }
137     return 0;
138 }
View Code

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3283

题目大意:

吐槽:HN2016省队集训原题,辣鸡出题人......

做法:对于操作1,没什么好说的,直接上快速幂即可。

对于操作2,如果p是质数,就是BSGS算法,否则,就用扩展BSGS算法;而实际上扩展BSGS可以解决p是质数,所以就不用分类讨论了。

对于(extended)baby_step_gaint_step算法,未完待续......

对于操作3,组合数取模,扩展lucas定理。

对于组合数取模,未完待续......

 

posted @ 2016-08-13 00:20  oyzx~  阅读(235)  评论(0编辑  收藏  举报