毒瘤\(xgzc,QwQ\)~~~~~~
\(PartA:gcd\)
额,具体思想与证明就不说了,这都不知道的话就退役去向欧几里得学数学吧……
inline int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
\(extend:exgcd\)
额,这也不用证吧,这不就\(yy\)一下就出来了吗~~
有解充要条件:
\[\text{在}~ ~ ~ax+by=c~ ~ ~\text{中有}~ ~ ~gcd(a,b)|c\]
不妨设\(ax+by=gcd(a,b)\),则有:
\[ax+by=gcd(a,b)=bx^{'}+(a~mod~b)y^{'}=gcd(b,a~mod~b)\]
移一下项就可以递归搞了:
int x,y;
inline void exgcd(int a,int b)
{
if(!b)
{
x=1,y=0;
return;
}
exgcd(b,a%b);
int tmp=x;
x=y;
y=tmp-a/b*y;
}
#include<bits/stdc++.h>
using namespace std;
#define in(a) a=read()
#define ll long long
inline ll read()
{
ll x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
ll jie[2];
inline ll gca(ll s,ll t)
{
if(t==0) return s;
return gca(t,s%t);
}
inline void getit(ll s,ll t)
{
if(t==0)
{
jie[0]=1;
jie[1]=0;
return;
}
getit(t,s%t);
ll u=jie[1],v=jie[0]-s/t*jie[1];
jie[0]=u;
jie[1]=v;
}
int main()
{
ll n,x,y,a,b;
in(x);in(y);in(a);in(b);in(n);
if(a<b) swap(a,b),swap(x,y);
ll delta=y-x;
ll q=gca(a-b,n);
if(delta%q!=0)
{
printf("Impossible\n");
return 0;
}
getit(a-b,n);
ll ans=jie[0]*delta/q;
ll r=n/q;
ans=(ans%r+r)%r;
printf("%lld\n",ans);
return 0;
}
\(PartB:\)费马小定理和欧拉定理
费马小定理:
\[a^{p-1}\equiv1\pmod{p}~~~ (d_p==1)\]
欧拉定理:
\[a^b\equiv a^{b\%\phi(n)}\pmod{n}\]
\(PartC:BSGS\)
主要功能是用于求解类似如下方程的解:
\[a^x\equiv b\pmod{c}\]
主元当然是\(x\)了\(QwQ\)~~~
额,面对柿子一开始就很懵逼,现在依旧……
好吧,现在蒟蒻的我依旧只会做法,希望将来有一天能够弄得透彻一点:
令\(m=\lceil \sqrt{p}\rceil,x=my+z(y,z\text{均为变量})\),则当\(a^x\equiv b\pmod{c}\)成立时有\(a^{my}* a^z\equiv b\pmod{c}\),移一下项就有\(a^{my}\equiv \frac{b}{a^z}\pmod{c}\),预处理出\(\forall z\in\left[1,m\right]\)的\(\frac{b}{a^z}\)并存在\(map\)里面,然后枚举\(y\)判有无解即可。
时间复杂度\(O(\sqrt{n})\):
inline int sol(int a,int b,int c)
{
if(!(a%c)) return -1;
int ans=b%c,m=ceil(sqrt(c));
mp[ans]=0;
fur(i,1,m)
{
ans=ans*a%c;
mp[ans]=i;
}
int tmp=power(a,m,c);ans=1;
fur(i,1,m)
{
ans=ans*tmp%c;
if(mp[ans]) return (i*m-mp[ans])%c+c)%c;
}
return -1;
}
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define cl(a,b) memset(a,b,sizeof(a))
#define jinitaimei signed
#define int long long
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
map <int,int> mp;
inline int power(int x,int k,int mod)
{
int res=1;
for(;k;k>>=1,x=x*x%mod) if(k&1) res=res*x%mod;
return res;
}
inline void sol(int a,int b,int c)
{
if(!(a%c))
{
puts("no solution");
return;
}
int ans=b%c,m=ceil(sqrt(c));
bool flag=false;
mp[ans]=0;
fur(i,1,m)
{
ans=ans*a%c;
mp[ans]=i;
}
int tmp=power(a,m,c);ans=1;
fur(i,1,m)
{
ans=ans*tmp%c;
if(mp[ans])
{
printf("%lld\n",((i*m-mp[ans])%c+c)%c);
flag=true;
break;
}
}
if(!flag) puts("no solution");
}
jinitaimei main()
{
int a,b,c;
while(scanf("%lld%lld%lld",&c,&a,&b)!=EOF)
{
mp.clear();
sol(a,b,c);
}
return 0;
}
\(extend:exbsgs\)(不是质数的情况)
这个\(xg\)说有点毒瘤,那就直接上柿子算了:
\[a^x\equiv b\pmod c\Rightarrow a^x+kc=b\]
\[\text{令}~g=gcd(a,c),\therefore\frac{b}{g}\in N^{* }\]
\[\Rightarrow \frac{a}{g}a^{x-1}+k\frac{p}{g}\equiv\frac{b}{g}\pmod{\frac{p}{g}}\]
\[\Rightarrow a^{x-1}\equiv \frac{b}{g}(\frac{a}{g})^{-1}\pmod{\frac{p}{g}}\]
\[\Rightarrow a^{x^{'}}\equiv b^{'}\pmod{m^{'}}(x^{'}=x-1,b^{'}=\frac{b}{g}(\frac{a}{g})^{-1},m^{'}=\frac{p}{g})\]
用类似于\(exgcd\)的思想递归即可
\(PartD:crt\)
这个是用来求同余方程组的:
\[\begin{cases}x\equiv a_1\pmod{p_1}\\x\equiv a_2\pmod{p_2}\\……\\x\equiv a_n\pmod {p_n}\end{cases}\]
其中\(p_i\)都是质数
貌似有个利用的栗子是韩信点兵??
还是说正常的吧:
(没模板题,就不给代码了)
\[\text{设}M=\prod\limits_{i=1}^n p_i,m_i=\frac{M}{p_i},t_i\equiv \frac{1}{m_i}\pmod{p_i}\]
\[\text{那么所求为}ans\equiv\sum a_it_im_i\pmod{M}\]
\(extend:excrt\text{(话说好多ex-QwQ)}\):
不是质数的情况有点难受
考虑两两合并方程,利用\(exgcd\)即可:
const int xx=1e5+1612;
int t[xx],p[xx];
int k1,k2,x,n,M;
inline int gcd(int a,int b){return !b?a:gcd(b,a%b);}
inline void exgcd(int a,int b)
{
if(!b)
{
k1=1,k2=0;
return;
}
exgcd(b,a%b);
int tmp=k1;
k1=k2;k2=tmp-a/b*k2;
}
inline int Fast_mul(int a,int b,int mod)
{
int res=0;
for(;b;b>>=1,a=(a+a)%mod) if(b&1) res=(res+a)%mod;
return res;
}
inline void excrt()
{
M=p[1];x=t[1];
fur(i,2,n)
{
int a=M,b=p[i];
int c=(t[i]-x%b+b)%b;
int tmp=gcd(a,b);
exgcd(a,b);
int lcm=b/tmp;
k1=Fast_mul(k1,c/tmp,lcm);
x+=k1*M;
M*=lcm;
x=(x%M+M)%M;
}
printf("%lld\n",x);
}
模板:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define cl(a,b) memset(a,b,sizeof(a))
#define jinitaimei signed
#define int long long
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
const int xx=1e5+1612;
int t[xx],p[xx];
int k1,k2,x,n,M;
inline int gcd(int a,int b){return !b?a:gcd(b,a%b);}
inline void exgcd(int a,int b)
{
if(!b)
{
k1=1,k2=0;
return;
}
exgcd(b,a%b);
int tmp=k1;
k1=k2;k2=tmp-a/b*k2;
}
inline int Fast_mul(int a,int b,int mod)
{
int res=0;
for(;b;b>>=1,a=(a+a)%mod) if(b&1) res=(res+a)%mod;
return res;
}
inline void sol()
{
M=p[1];x=t[1];
fur(i,2,n)
{
int a=M,b=p[i];
int c=(t[i]-x%b+b)%b;
int tmp=gcd(a,b);
exgcd(a,b);
int lcm=b/tmp;
k1=Fast_mul(k1,c/tmp,lcm);
x+=k1*M;
M*=lcm;
x=(x%M+M)%M;
}
printf("%lld\n",(x%M+M)%M);
}
inline void init()
{
n=in;
fur(i,1,n) p[i]=in,t[i]=in;
}
jinitaimei main()
{
init();
sol();
return 0;
}
屠龙勇士:
思路还蛮有意思的,需要看清楚题,分两种情况(可用\(excrt\)的与不可用但不需用的),然后列式子,化简方程,最后用模板搞事情就可以啦:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define jinitaimei signed
#define int long long
const int xx=1e5+1612;
int t[xx],p[xx],cnt;
int k1,k2,x,n,M;
int tmp1[xx],tmp2[xx],tmp3[xx],tmp4[xx];
bool flag;
multiset <int> s;
multiset <int>:: iterator it;
inline int gcd(int a,int b){return !b?a:gcd(b,a%b);}
inline void exgcd(int a,int b)
{
if(!b)
{
k1=1,k2=0;
return;
}
exgcd(b,a%b);
int tmp=k1;
k1=k2;
k2=tmp-a/b*k2;
}
inline int Fast_mul(int a,int b,int mod)
{
int res=0;
if(b<0) return 1;
for(;b;b>>=1,a=(a+a)%mod) if(b&1) res=(res+a)%mod;
return res;
}
inline void sol()
{
if(flag) return;
M=p[1];x=t[1];
fur(i,2,cnt)
{
int a=M,b=p[i];
int c=((t[i]-x%b+b)%b+b)%b;
int tmp=gcd(a,b);
exgcd(a,b);
int lcm=b/tmp;
if(c%tmp)
{
puts("-1");
return;
}
k1=Fast_mul(k1,c/tmp,lcm);
x+=k1*M;
M*=lcm;
x=(x%M+M)%M;
}
printf("%lld\n",(x%M+M)%M);
}
inline void init()
{
s.clear();
flag=false;cnt=0;
int tmp=0,m;
scanf("%lld%lld",&n,&m);
fur(i,1,n) scanf("%lld",&tmp1[i]);
fur(i,1,n){scanf("%lld",&tmp2[i]);if(tmp2[i]<tmp1[i]) flag=true;}
fur(i,1,n) scanf("%lld",&tmp4[i]);
fur(i,1,m) scanf("%lld",&tmp3[i]);
fur(i,1,m) s.insert(tmp3[i]);
fur(i,1,n)
{
it=(tmp1[i]<(*s.begin()))?s.begin():(--s.upper_bound(tmp1[i]));
tmp3[i]=*it;
s.erase(it);
s.insert(tmp4[i]);
}
if(flag)
{
fur(i,1,n) tmp=max(tmp,(int)ceil((double)tmp1[i]/(double)tmp3[i]));
printf("%lld\n",tmp);
}
}
inline void handle()
{
if(flag) return;
fur(i,1,n)
{
if(tmp1[i]==tmp3[i]) continue;
int tmp=gcd(tmp3[i],tmp2[i]);
exgcd(tmp3[i],tmp2[i]);
if(tmp1[i]%tmp)
{
puts("-1"),flag=true;
return;
}
k1=Fast_mul(k1,tmp1[i]/tmp,tmp2[i]/tmp);
t[++cnt]=k1;
p[cnt]=tmp2[i]/tmp;
}
}
jinitaimei main()
{
int T;
scanf("%lld\n",&T);
while(T--)
{
init();
handle();
sol();
}
return 0;
}
\(PartE:Lucas\)
给个式子就好了,相信你们都会,逃……(\(p\)是质数):
\[C^m_n\equiv C_{n\%p}^{m\%p}* C_{n/p}^{m/p}\pmod{p}\]
模板:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define in read()
#define fur(i,a,b) for(int i=a;i<=b;i++)
inline ll read()
{
ll x=0,f=1;char ch=getchar();
for(;!isalnum(ch);ch=getchar()) if(ch=='-') f=-1;
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x*f;
}
inline ll power(ll a,ll b,ll mod)
{
ll ans=1;
while(b>0)
{
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll jc[250000];
inline ll lucas(ll m,ll n,ll mod)
{
if(m>n) return 0;
if(m==0) return 1;
if(m<mod&&n<mod) return jc[n]*power(jc[m]*jc[n-m]%mod,mod-2,mod)%mod;
return lucas(m/mod,n/mod,mod)*lucas(m%mod,n%mod,mod)%mod;
}
int main()
{
ll t;t=in;
while(t--)
{
ll n,m,p;
n=in;m=in;p=in;
jc[0]=1;
fur(i,1,n+m) jc[i]=i*jc[i-1]%p;
printf("%lld\n",lucas(m,n+m,p));
}
return 0;
}
\(extend:exLucas\):
这个需要不厌其烦地用\(crt\)去分模数使得式子可以满足普通式的条件
暂时太菜,就不给代码了(真的不是我不会)
\(PartF:\text{二次剩余}\)
时间原因,还要改考试题,放个大佬博客在这里先,下次再来写
#include<bits/stdc++.h>
using namespace std;
#define in read()
#define re register
#define fur(i,a,b) for(re int i=a;i<=b;++i)
#define fdr(i,a,b) for(re int i=a;i>=b;--i)
#define cl(a,b) memset(a,b,sizeof(a))
#define jinitaimei signed
#define int long long
inline int read()
{
int x=0;
char ch=getchar();
for(;!isalnum(ch);ch=getchar());
for(;isalnum(ch);ch=getchar()) x=x*10+ch-'0';
return x;
}
struct num
{
int x,y;
};
int w,q;
inline num times(num a,num b,int p)
{
num ans;
ans.x=(a.x*b.x%p+a.y*b.y%p*w%p+p)%p;
ans.y=(a.y*b.x%p+a.x*b.y%p+p)%p;
return ans;
}
inline int pow1(num a,int b,int p)
{
num ans={1,0};
for(;b;b>>=1,a=times(a,a,p)) if(b&1) ans=times(ans,a,p);
return ans.x%p;
}
inline int pow2(int a,int b,int p)
{
int ans=1;
for(;b;b>>=1,a=a*a%p) if(b&1) ans=ans*a%p;
return ans%p;
}
inline int sol(int n,int p)
{
n%=p;
if(pow2(n,(p-1)/2,p)==p-1) return -1;
while(true)
{
q=rand()%p;
w=(q*q%p-n%p+p)%p;
if(pow2(w,(p-1)/2,p)==p-1) break;
}
return pow1((num){q,1},(p+1)/2,p);
}
jinitaimei main()
{
int T=in;
while(T--)
{
int n=in,p=in;
if(!n)
{
puts("0");
continue;
}
int ans1=sol(n,p),ans2=p-ans1;
if(ans1==-1) puts("Hola!");
else
{
if(ans1==ans2) printf("%lld\n",ans1);
else if(ans1<ans2) printf("%lld %lld\n",ans1,ans2);
else printf("%lld %lld\n",ans2,ans1);
}
}
return 0;
}