青蛙的约会poj1061
设两只青蛙跳了T次
由题意可知
Tn+X=Tm+y≡w(mod L) //w为任意数
因为它们在环上运动,所以可以把式子转化一下
Tn-Tm≡X-Y(mod L)
即 T(n-m)+Lp=X-Y(p为整数)
一看这个式子很眼熟,这不就是ax+by=c吗
所以可以用扩展欧几里得算法解这个不等式
因为要计算最小正整数解,x=(x%(L/d)+L/d)%(L/d); //d=gcd(n-m,L)
为什么要x=(x%(L/d)+L/d)%(L/d);??
这里讲的很清楚 https://www.luogu.org/problemnew/solution/P1516
上代码
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include<cmath> #define ll long long using namespace std; const int maxn=1000000+10101; inline ll read(){ ll x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0'; return x*f; } void exgcd(ll a,ll b,ll &d,ll &x,ll &y){ if(!b){ d=a;x=1;y=0; return; } exgcd(b,a%b,d,x,y); int t=x;x=y; y=t-(a/b)*y; return ; } ll X,Y,m,n,l; int main(){ X=read();Y=read();m=read();n=read();l=read(); ll d,a,b; if(n<m){swap(n,m);swap(X,Y);} exgcd(n-m,l,d,a,b); if((X-Y)%d!=0 || m==n){printf("Impossible");return 0;} a=a*(X-Y)/d+l/d; a=(a%(l/d)+l/d)%(l/d); printf("%lld",a); return 0; }
同余方程noip2012
这道题裸地扩欧
ax≡1(mod b)
ax+by=1;
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include<cmath> #define ll long long using namespace std; const int maxn=1000000+10101; inline ll read(){ ll x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0'; return x*f; } void exgcd(ll a,ll b,ll &d,ll &x,ll &y){ if(!b){ x=1;y=0;d=a; return ; } exgcd(b,a%b,d,x,y); int t=x;x=y; y=t-(a/b)*y; return ; } ll a,b,x,y,d; int main(){ a=read();b=read(); exgcd(a,b,d,x,y); printf("%lld",(x+b)%b); return 0; }
Sumdiv poj1845
这道题首先要了解一个数的约数和的公式
然后对每个质因子进行等比数列公式求和
公式为(a^(n+1)-1)/(a-1) (a为一个数的任意质因子,n为这个质因子的个数)
所以我们用快速幂求a^(n+1), 用逆元求1/(a-1)
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include<cmath> #define ll long long using namespace std; const int maxn=1000000+10101; const int MOD=9901; inline ll read(){ ll x=0,f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=(x<<3)+(x<<1)+ch-'0'; return x*f; } ll m,A,B,p[20],c[20]; void divide(ll n){ //质因数分解 for(ll i=2;i*i<=n;i++){ if(n%i==0){ p[++m]=i; while(n%i==0)n/=i,c[m]++; c[m]*=B; } } if(n>1)p[++m]=n,c[m]=B; return ; } void exgcd(ll a,ll b,ll &d,ll &x,ll &y){ //扩欧 if(!b){ d=a;x=1;y=0; return ; } exgcd(b,a%b,d,x,y); ll t=x;x=y; y=t-a/b*y; return; } ll power(ll a,ll b){ //快速幂 ll c=1; while(b){ if(b&1)c=(c*a)%MOD; b>>=1; a=(a*a)%MOD; } return c%MOD; } int main(){ A=read();B=read(); divide(A); ll ans=1; for(ll i=1;i<=m;i++){ if((p[i]-1)%MOD==0){ //没有逆元,特判 ans=((c[i]+1)*ans)%MOD; continue; } ll kk=(power(p[i],c[i]+1)%MOD-1+MOD)%MOD; ll d,x,y; exgcd(p[i]-1,MOD,d,x,y); x=((x/d)%(MOD/d)+(MOD/d))%(MOD/d)%MOD; //用等比数列公式求出约数和 ans=(ans*kk*x)%MOD; } printf("%lld",ans); return 0; }