1. 程式人生 > >POJ3243:Clever Y——題解

POJ3243:Clever Y——題解

++ code ostream AI names 整數 是的 += cnblogs

http://poj.org/problem?id=3243

求最小的非負整數y滿足x^y=k(mod z)

寫完板子之後等待了半個小時poj才終於進入……

poj不行啊.jpg

以前一直覺得BSGS太神啦於是就跳了。

結果回頭一看發現異常的簡單。

(老年化初步體現flag*1)

首先x^y對k取模隨著y的變化有周期性,最大周期不超過k(感性證明吧)

那麽最小的y一定是在[0,k)之間了。

我們把這段區間分塊,大小為n=sqrt(k),令m=k/n,則y=i*m-a,把y^a預處理移項到右面,hash表存一下就成了O(sqrt(k))的問題了。

是的就這麽簡單(當然如果存在gcd(x,k)!=1不存在逆元的話還得exgcd處理一下才行)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
typedef long long ll;
const int N=999979;
const int M=50005;
struct HASH{
    int w,to,nxt;
}h[M];
int cnt,head[N]; inline void add(int x,int y){ int t=x%N; for(int i=head[t];i;i=h[i].nxt){ int v=h[i].to; if(v==x){ h[i].w=y;//記大的 return; } } h[++cnt].to=x;h[cnt].w=y;h[cnt].nxt=head[t];head[t]=cnt; } inline int query(int x){
int t=x%N; for(int i=head[t];i;i=h[i].nxt){ int v=h[i].to; if(v==x)return h[i].w; } return -1; } int gcd(int a,int b){ return (!b)?a:gcd(b,a%b); } int exgcd(int a,int b,int &x,int &y){ if(!b){ x=1,y=0; return a; } int ans=exgcd(b,a%b,y,x); y-=(ll)(a/b)*x; return ans; } int inv(int a,int c){ int x,y; exgcd(a,c,x,y); return (x%c+c)%c; } //a^x=b(mod c); int BSGS(int a,int b,int c){ if(!a){ if(!b)return 1; return -1; } int tot=0,g,d=1; while((g=gcd(a,c))!=1){ if(b%g)return -1; ++tot;b/=g,c/=g; d=(ll)d*(a/g)%c; } b=(ll)b*inv(d,c)%c; cnt=0;memset(head,0,sizeof(head)); int s=sqrt(c),p=1; for(int i=0;i<s;i++){ if(p==b)return i+tot; add((ll)p*b%c,i); p=(ll)p*a%c; } int q=p; for(int i=s;i-s+1<c;i+=s){ int t=query(q); if(t!=-1)return i-t+tot; q=(ll)q*p%c; } return -1; } int main(){ int x,z,k; while(scanf("%d%d%d",&x,&z,&k)&&(ll)x+z+k>0){ x%=z,k%=z; int ans=BSGS(x,k,z); if(ans==-1)puts("No Solution"); else printf("%d\n",ans); } return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

POJ3243:Clever Y——題解