联考20200603 T1 解码

题目:


分析:
考场上暴力都不会写。。。(辣鸡出题人暴力分都没有

发现(n=pq,q-pleq 3e5)这个条件比较有趣,我们从这里入手
(q-p=y)
(n=p(p+y))
解一元二次方程,舍掉(-Delta)
(p=frac{-y+sqrt{y^2+4n}}{2})
(t=frac{y}{2})
所以(p=-t+sqrt{t^2+n})
因为(p)是整数,所以(t^2+n=k^2)(k)为整数)
我们分析前三个subtask发现((p,q))中无质数,推测(t)为一个很小的数,于是我们暴力枚举
最后一个subtask由于没有上面的保证,但是(p)(1e9)级别,那么(sqrt{n})也在(1e9)级别
我们需要(sqrt{k^2-n})为整数,且不大于(3e5)
那么(k^2-n)不大于(9e10)
暴力从(sqrt{n})开始枚举(k)(k)每加一便会使(k^2-n)增加(1e9)级别的量
那么(k)最多每枚举(frac{9e10}{1e9}=90)
暴力枚举就好了

果然是人类智慧tqlOrz

解出了素数(p,q),我们知道(gcd(c,(p-1)(q-1)=varphi(n))=1),我们解出(d)使得(cdequiv 1(mod varphi(n)))
根据欧拉定理,(xequiv x^{cd}equiv m^d(mod n))
快速幂

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<iostream>
#include<map>
#include<bitset>
#include<string>

#define maxn 300005
#define INF 1<<30
#define eps 1e-13

using namespace std;

inline long long getint()
{
    long long num=0,flag=1;char c;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
    while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
    return num*flag;
}

long long n,m,c,p,q;
long long sq[maxn];

inline long long mul(long long a,long long b,long long p)
{return (a*b-(long long)((long double)a/p*b+eps)*p+p)%p;}
inline long long ksm(long long num,long long k,long long MOD)
{
	long long ret=1;
	for(;k;k>>=1,num=mul(num,num,MOD))if(k&1)ret=mul(ret,num,MOD);
	return ret;
}
inline long long sqr(long long x){return x*x;}
inline void exgcd(long long a,long long b,long long &x,long long &y)
{
	if(!b){x=1,y=0;return;}
	exgcd(b,a%b,y,x);y-=a/b*x;
}

int main()
{
	int T=getint();
	for(int i=1;i<=300000;i++)sq[i]=sqr(i);
	while(T--)
	{
		n=getint(),m=getint(),c=getint();
		long long k=sqrt(n),t;
		for(;(t=sqr(k))-n<=sq[300000];k++)
		{
			int l=lower_bound(sq,sq+300001,t-n)-sq;
			if(sq[l]==t-n){p=k-l,q=k+l;break;}
		}
		long long x,y,P=(p-1)*(q-1);
		exgcd(c,P,x,y);
		x=(x%P+P)%P;
		printf("%lld
",ksm(m,x,n));
	}
}

原文地址:https://www.cnblogs.com/Darknesses/p/13038343.html