2019 杭电 多校第3场 1006 Fansblog (HDU 6608)
题目链接
题解:
用威尔逊定理变换,然后求逆元。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(a==0&&b==0) return -1;
if(b==0) {x=1;y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
ll inv(ll a,ll m) // 求a关于m的逆元 。 扩展欧几里得求逆元,用这个方法,函数运算过程不会爆long long
{
ll x,y;
ll d=exgcd (a,m,x,y);
if(d==1)
return (x%m+m)%m;
else return -1;
// if(a==1)
// return 1;
// return inv(m%a,m)*(m-m/a)%m;
}
int isprime(ll x)
{
if(x==2) return 1;
if(x<2) return 0;
ll sqx=(ll)sqrtl(x);
for(int i=2 ;i<=sqx;++i)
if(x%i==0)
return 0;
return 1;
}
ll p,x;
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>p;
__int128 product=1;
for(ll i=p-1; ;--i)
{
if(isprime(i))
{
x=i;
// printf("%lld\n",i);
break;
}
if(i<=p-2)
product=product*i%p;
}
ll a=product;
printf("%lld\n",inv(a,p));
}
return 0;
}
另一种求逆元写法:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y)
{
if(a==0&&b==0) return -1;
if(b==0) {x=1;y=0;return a;}
ll d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
__int128 inv(ll a,ll m) // 求a关于m的逆元。简洁写法
{
// ll x,y;
// ll d=exgcd (a,m,x,y);
// if(d==1)
// return (x%m+m)%m;
// else return -1;
if(a==1)
return 1;
return inv(m%a,m)*(m-m/a)%m;
}
int isprime(ll x)
{
if(x==2) return 1;
if(x<2) return 0;
ll sqx=(ll)sqrtl(x);
for(int i=2 ;i<=sqx;++i)
if(x%i==0)
return 0;
return 1;
}
ll p,x;
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>p;
__int128 product=1;
for(ll i=p-1; ;--i)
{
if(isprime(i))
{
x=i;
// printf("%lld\n",i);
break;
}
if(i<=p-2)
product=product*i%p;
}
ll a=product;
ll ans=inv(a,p)%p;
printf("%lld\n",ans);
}
return 0;
}