您的位置:首页 > 其它

【BZOJ】【2219】数论之神

2015-06-02 17:17 495 查看

中国剩余定理+原根+扩展欧几里得+BSGS

  题解:http://blog.csdn.net/regina8023/article/details/44863519

  新技能get√:

/**************************************************************
Problem: 2219
User: Tunix
Language: C++
Result: Accepted
Time:288 ms
Memory:5076 kb
****************************************************************/

//BZOJ 2219
#include<cmath>
#include<map>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
typedef long long LL;
inline int getint(){
int r=1,v=0; char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1;
for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch;
return r*v;
}
const int N=1e5+10;
const LL inf=1e18;
/*******************template********************/

map<LL,LL> mp;
struct data{
LL p,c,pc;
}a
;
int num,cnt;
LL f
;
void Split(int x){
num=0;
for(int i=2;i*i<=x;i++)
if (x%i==0){
a[++num].p=i;
a[num].c=0; a[num].pc=1;
while(x%i==0)
x/=i,a[num].c++,a[num].pc*=i;
if (x==1) break;
}
if (x!=1)
a[++num].p=x,a[num].pc=x,a[num].c=1;
}
LL Pow(LL a,LL b,LL p){
LL r=1;
for(;b;b>>=1,a=a*a%p) if (b&1) r=r*a%p;
return r;
}

LL Get_yuangen(LL p,LL phi){
int c=0;
for(int i=2;i*i<=phi;i++)
if (phi%i==0)
f[++c]=i,f[++c]=phi/i;
for(int g=2;;g++){
int j;
for(j=1;j<=c;j++) if (Pow(g,f[j],p)==1) break;
if (j==c+1) return g;
}
return 0;
}

void exgcd(LL a,LL b,LL &d,LL &x,LL &y){
if (!b) {d=a;x=1;y=0;return;}
else{exgcd(b,a%b,d,y,x); y-=x*(a/b);}
}

LL BSGS(LL A,LL B,LL C){
int m=ceil(sqrt(C+0.5));
mp.clear();
LL now=1;
F(i,1,m){
now = now*A%C;
if (!mp[now]) mp[now]=i;
}
mp[1]=0;
A=Pow(A,m,C);
now=1LL;
F(i,0,m){
LL d,x,y;
exgcd(now,C,d,x,y);
x=(x*B%C+C)%C;
if (mp.count(x)) return i*m+mp[x];
now=now*A%C;
}
return 0;
}

LL gcd(LL a,LL b){return b ? gcd(b,a%b) : a;}

LL solve(LL A,LL B,LL k){
LL phi=a[k].pc-a[k].pc/a[k].p,
g=Get_yuangen(a[k].pc,phi);
LL ind=BSGS(g,B,a[k].pc);
LL ans=gcd(phi,A);
if (ind%ans) return 0;
return ans*Pow(a[k].p,cnt-cnt/A,inf);
}

int main(){
#ifndef ONLINE_JUDGE
freopen("2219.in","r",stdin);
freopen("2219.out","w",stdout);
#endif
int T=getint();
while(T--){
LL A=getint(),B=getint(),k=getint();
LL p=2*k+1;
Split(p);
LL ans=1;
F(i,1,num){
if (!ans) break;
if (B%a[i].pc==0)
ans=ans*Pow(a[i].p,a[i].c-(a[i].c-1)/A-1,inf);
else{
int b=B;
cnt=0;
while((b%a[i].p)==0){
b/=a[i].p;
a[i].pc/=a[i].p;
a[i].c--,cnt++;
}
if (cnt % A) ans=0;
else ans=ans*solve(A,b,i);
}
}
printf("%lld\n",ans);
}
return 0;
}


View Code

2219: 数论之神

Time Limit: 3 Sec Memory Limit: 259 MB
Submit: 410 Solved: 48
[Submit][Status][Discuss]

Description


ACM_DIY群中,有一位叫做“傻崽”的同学由于在数论方面造诣很高,被称为数轮之神!对于任何数论问题,他都能瞬间秒杀!一天他在群里面问了一个神
题: 对于给定的3个非负整数 A,B,K 求出满足 (1) X^A = B(mod 2*K + 1) (2) X 在范围[0, 2K]
内的X的个数!自然数论之神是可以瞬间秒杀此题的,那么你呢?

Input

第一行有一个正整数T,表示接下来的数据的组数( T <= 1000) 之后对于每组数据,给出了3个整数A,B,K (1 <= A, B <= 10^9, 1 <= K <= 5 * 10^8)

Output

输出一行,表示答案

Sample Input

3

213 46290770 80175784

3 46290770 80175784

3333 46290770 80175784

Sample Output

27

27

297

HINT

新加数组一组--2015.02.27

Source

数论 鸣谢 AekdyCoin

[Submit][Status][Discuss]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: