浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ2242: [SDOI2011]计算器

Description

你被要求设计一个计算器完成以下三项任务:

1、给定y,z,p,计算Y^Z Mod P 的值;

2、给定y,z,p,计算满足xy≡ Z ( mod P )的最小非负整数;

3、给定y,z,p,计算满足Y^x ≡ Z ( mod P)的最小非负整数。

Input

输入包含多组数据。

第一行包含两个正整数T,K分别表示数据组数和询问类型(对于一个测试点内的所有数据,询问类型相同)。

以下行每行包含三个正整数y,z,p,描述一个询问。

Output

对于每个询问,输出一行答案。对于询问类型2和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”,注意逗号与“I”之间有一个空格。

Sample Input

【样例输入1】
3 1
2 1 3
2 2 3
2 3 3
【样例输入2】
3 2
2 1 3
2 2 3
2 3 3
【数据规模和约定】
对于100%的数据,1<=y,z,p<=10^9,P为质数,1<=T<=10。

Sample Output

【样例输出1】
2
1
2
【样例输出2】
2
1
0

Solution

这种强行拼题真的好吗...
(一道题当T1,T2,T3用)
其实是板子题来着
第一问显然直接快速幂,第二问是exgcd,第三问是bsgs
这里讲一下bsgs的过程:

\[已知量:Y\space P\space Z\space m\\ Y^x\space \equiv Z\space (mod\space p)\\ 求x\\ 设m=\lceil \sqrt{P} \rceil\\ 则x=i*m-j \\ Y^{i*m-j}\equiv Z(mod\space P)\\ Y^{i*m}\equiv(Z*Y^j) (mod\space P)\\ \]

所以只需要开一个map,存一下\(Z*Y^j\)的值,然后枚举i,第一个枚举出来的答案就是最小值

#include <bits/stdc++.h>
#define ll long long

int T, k;
ll y, z, p;

ll power(ll a, ll b) {
    ll ans = 1, base = a;
    while(b) {
        if(b & 1) ans = (ans * base) % p;
        base = (base * base) % p;
        b >>= 1;
    }
    return ans % p;
}

ll exgcd(ll a, ll b, ll &x, ll &y) {
    if(b == 0) {return x = 1, y = 0, a;}
    ll ans = exgcd(b, a % b, x, y), tmp = x;
    x = y; y = tmp - (a / b) * y;
    return ans;
}

std::map<ll , ll> mp;
void bsgs() {
    mp.clear(); z %= p;
    ll m = std::sqrt(p); if(m % p) ++ m; 
    for(ll i = 0, tmp = 1; i <= m; i ++, tmp = tmp * y % p) {
    	mp[z * tmp % p] = i;
    }
    if(power(y , m) == 0) {
    	if(z == 1) puts("1");
    	else puts("Orz, I cannot find x!");
    	return;
    }
    for(ll i = 1; i <= m; i ++) {
    	ll tmp = power(y, i * m), j = mp[tmp];
    	if(j == 0) continue;
    	if(i * m - j >= 0) {
    		printf("%lld\n", i * m - j);
    		return;
    	}
    }
    puts("Orz, I cannot find x!");
}

int main() {
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif 
    scanf("%d%d", &T, &k);
    while(T--) {
        scanf("%lld%lld%lld", &y, &z, &p);
        if(k == 1) {
            printf("%lld\n", power(y, z));
        } else if(k == 2) {
            ll a1, a2, g;
            y %= p; z %= p;
            g = exgcd(y ,p ,a1 ,a2);
            if(z % g) puts("Orz, I cannot find x!"); 
            else {
                ll tmp = p / g;
                a1 = ((a1 * z) % tmp + tmp) % tmp;
                printf("%lld\n", a1);
            }
        } else bsgs();
    }
    return 0;
}
posted @ 2018-12-16 11:51  henry_y  阅读(164)  评论(0编辑  收藏  举报