1⃣️扩展欧几里得算法
sgu 141 扩展欧几里德+枚举大法,不过sgu好像崩了。。。。
poj 2891
合并模方程式
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
typedef long long ll;
ll K;
ll a[N],r[N];
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Exgcd(ll a,ll b,ll &x,ll &y,ll &d)
{
if(b==0)
{
d=a;x=1;y=0;
return;
}
Exgcd(b,a%b,y,x,d);
y-=a/b*x;
}
ll work()
{
ll Last_a=a[1],Last_r=r[1],x,y,d;
for(int i=2;i<=K;i++)
{
Exgcd(Last_a,a[i],x,y,d);
if((r[i]-Last_r)%d!=0)
return -1;
ll tmp=a[i]/d;
x=((r[i]-Last_r)/d*x)%tmp;
Last_r+=x*Last_a;
Last_a=Last_a/d*a[i];
Last_r%=Last_a;
}
return Last_r>0?Last_r:Last_r+Last_a;
}
int main()
{
while(scanf("%lld",&K)!=EOF)
{
for(ll i=1;i<=K;i++)
{
a[i]=read();r[i]=read();
}
printf("%lld\n",work());
}
return 0;
}
2⃣️Miller-Rabbin 素数检测法
1.费马小定理
2.二次探测定理
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
const int S=3;
int K,Ans;
ll A[4]={0,2,7,61}; //黑科技一波
inline ll read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll Quick_mul(ll a,ll b,ll n)
{
ll base=a,r=0;
while(b)
{
if(b&1)
r=(r+base)%n;
base=(base+base)%n;
b>>=1;
}
return r;
}
ll Quick_pow(ll a,ll exp,ll n)
{
ll base=a,r=1;
while(exp)
{
if(exp&1)
r=r*base%n;
base=base*base%n;
exp>>=1;
}
return r;
}
bool Miller_Rabbin(ll n)
{
if(n==2)return true;
int t=0;
ll a,x,y,u=n-1;
while(!(u&1))
{
t++;u>>=1;
}
for(int i=1;i<=S;i++)
{
a=A[i];
x=Quick_pow(a,u,n);
for(int j=1;j<=t;j++)
{
y=Quick_mul(x,x,n);
if(y==1&&x!=1&&x!=n-1)
return false;
x=y;
}
if(x!=1)
return false;
}
return true;
}
int main()
{
while(scanf("%d",&K)!=EOF)
{
Ans=0;
for(int i=1;i<=K;i++)
{
ll n=read();
if(Miller_Rabbin(n))
Ans++;
}
printf("%d\n",Ans);
}
return 0;
}
3⃣️.快速求逆元
4⃣️卢卡斯定理 ---组合数取模
Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)
1.hdu 3037 Saving Beans
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
typedef long long ll;
int T;
ll n,m,p;
ll pre[N],S_pre[N];
ll Quick_mul(ll a,ll b)
{
ll base=a,r=0;
while(b)
{
if(b&1)
r=(r+base)%p;
base=(base+base)%p;
b>>=1;
}
return r;
}
ll Quick_pow(ll a,ll exp)
{
ll base=a,r=1;
while(exp)
{
if(exp&1)
r=Quick_mul(r,base);
base=Quick_mul(base,base);
exp>>=1;
}
return r;
}
void Prepare()
{
pre[0]=1;
for(int i=1;i<=p;i++)
pre[i]=pre[i-1]*i%p;
S_pre[p-1]=Quick_pow(pre[p-1],p-2);
for(int i=(int)p-2;i>=1;i--)
S_pre[i]=S_pre[i+1]*(i+1)%p;
S_pre[0]=1;
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%lld%lld%lld",&n,&m,&p);
n+=m;
Prepare();
ll Ans=1;
while(n||m)
{
ll t1=n%p,t2=m%p;
if(t1<t2)
{
Ans=0;break;
}
ll tmp=((pre[t1]*S_pre[t1-t2])%p*S_pre[t2])%p;
Ans=Ans*tmp%p;
n/=p;m/=p;
}
printf("%lld\n",Ans);
}
return 0;
}
5⃣️.中国剩余定理
网上看了好多都是在乱扯。。。强行把欧几里德题解说成中国剩余定理 如上poj 2891
1.hdu 1370 Biorhythms
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 10
typedef long long ll;
ll A[N],B[N],C[N];
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Exgcd(ll a,ll b,ll &x,ll &y,ll &d)
{
if(b==0)
{
d=a;x=1;y=0;
return;
}
Exgcd(b,a%b,y,x,d);
y-=a/b*x;
}
int main()
{
ll Zy=read();
ll Lim_min,x,y,d;
ll Mul=23*28*33;
Exgcd(Mul/23,23,x,y,d);B[1]=x;C[1]=23;
Exgcd(Mul/28,28,x,y,d);B[2]=x;C[2]=28;
Exgcd(Mul/33,33,x,y,d);B[3]=x;C[3]=33;
int Case=0;
while(scanf("%lld%lld%lld%lld",&A[1],&A[2],&A[3],&Lim_min))
{
if(A[1]==-1&&A[2]==-1&&A[3]==-1&&Lim_min==-1)
break;
ll Ans=0;
for(int i=1;i<=3;i++)
{
Ans=(Ans+Mul/C[i]*B[i]*A[i])%Mul;
}
if(Ans<=Lim_min)
{
ll qwer=(Lim_min-Ans)/Mul+1;
Ans+=qwer*Mul;
}
printf("Case %d: the next triple peak occurs in %lld days.\n",++Case,Ans-Lim_min);
}
return 0;
}
6⃣️欧拉函数与莫比乌斯函数
1.hdu 2824 (线性筛求欧拉函数)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 3000010
int a,b,tot;
int phi[N],Prime[N/3];
bool flag[N];
void Prepare()
{
for(int i=2;i<=3000000;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
phi[i]=i-1;
}
for(int j=1;(long long)Prime[j]*i<=3000000;j++)
{
flag[i*Prime[j]]=1;
if(i%Prime[j]==0)
{
phi[i*Prime[j]]=phi[i]*Prime[j];
break;
}
else
phi[i*Prime[j]]=phi[i]*(Prime[j]-1);
}
}
}
int main()
{
Prepare();
while(scanf("%d%d",&a,&b)!=EOF)
{
long long Ans=0;
for(int i=a;i<=b;i++)
Ans+=phi[i];
printf("%lld\n",Ans);
}
return 0;
}
2.求 ∑gcd(i,j) 1≤i≤n , 1≤j≤m
Orz KZF
其过程就是不断替换求和公式的变量得到新的求和公式(瞎bb的)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
int n,m,tot;
int Prime[N],phi[N];
bool flag[N];
void Prepare()
{
phi[1]=1;
for(int i=2;i<=100000;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
phi[i]=i-1;
}
for(int j=1;(long long)Prime[j]*i<=100000;j++)
{
flag[i*Prime[j]]=true;
if(i%Prime[j]==0)
{
phi[i*Prime[j]]=phi[i]*Prime[j];
break;
}
else
phi[i*Prime[j]]=phi[i]*(Prime[j]-1);
}
}
}
int main()
{
Prepare();
int a,b;scanf("%d%d",&a,&b);
n=min(a,b);m=max(a,b);
long long Ans=0;
for(int i=1;i<=n;i++)
{
Ans+=(long long)(n/i)*(m/i)*phi[i];
}
cout<<Ans<<endl;
return 0;
}
那么如果n是10^9数量级的呢?
让我们继续orz
复杂度s
是O(n^0.67)
3.poj 2480 (被网上坑了。。。看了好久。。暴力不就行了么,推个毛公式啊)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 1000010
int n,tot;
int Prime[N];
bool flag[N];
void Prepare()
{
for(int i=2;i<=1000000;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
}
for(int j=1;(long long)Prime[j]*i<=1000000;j++)
{
flag[i*Prime[j]]=true;
if(i%Prime[j]==0)
break;
}
}
}
int Get_phi(int k)
{
if(k==1)return 1;
int num=k;
for(int i=1;i<=tot;i++)
{
if(k%Prime[i]==0)
{
num=num/Prime[i]*(Prime[i]-1);
while(k%Prime[i]==0)
k/=Prime[i];
if(k==1)
break;
}
}
if(k!=1)
num=num/k*(k-1);
return num;
}
int main()
{
Prepare();
while(scanf("%d",&n)!=EOF)
{
long long Ans=0;
for(int i=1;i<=sqrt((double)n);i++)
{
if(n%i==0)
{
Ans+=(long long)i*Get_phi(n/i);
if(i!=(n/i))
{
int t=n/i;
Ans+=(long long)t*Get_phi(i);
}
}
}
printf("%lld\n",Ans);
}
return 0;
}
4.NYOJ 1066 CO—PRIME
莫比乌斯反演
此题中,设F(d)表示n个数中gcd为d的倍数的数有多少对,f(d)表示n个数中gcd恰好为d的数有多少对,
则F(d)=∑f(n) (n % d == 0)
f(d)=∑mu[n / d] * F(n) (n %d == 0)
---------> f(1)=∑mu[n] * F(n)
.......(摘抄From http://blog.youkuaiyun.com/lyhvoyage/article/details/38455415)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
int n,tot,Max;
int A[N],Prime[N],mu[N],num[N],cnt[N];
bool flag[N];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Prepare()
{
mu[1]=1;
for(int i=2;i<=100000;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
mu[i]=-1;
}
for(int j=1;(long long)i*Prime[j]<=100000;j++)
{
flag[i*Prime[j]]=true;
if(i%Prime[j]==0)
{
mu[i*Prime[j]]=0;
break;
}
else
mu[i*Prime[j]]=mu[i]*(-1);
}
}
}
int main()
{
Prepare();
while(scanf("%d",&n)!=EOF)
{
Max=0;
memset(num,0,sizeof(num));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
{
A[i]=read();
Max=max(Max,A[i]);num[A[i]]++;
}
for(int i=1;i<=Max;i++)
{
for(int j=i;j<=Max;j+=i)
cnt[i]+=num[j];
}
long long Ans=0;
for(int i=1;i<=Max;i++)
{
Ans+=(long long)mu[i]*cnt[i]*(cnt[i]-1)/2;
}
printf("%lld\n",Ans);
}
return 0;
}
5.bzoj 2820 YY的GCD
莫比乌斯函数
orz Hzwer.......
在维护一个前缀和做。。。。。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 10000010
int n,m,tot,Max;
int A[N],Prime[N],mu[N],num[N],cnt[N],F[N];
long long sum[N];
bool flag[N];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Prepare()
{
mu[1]=1;
for(int i=2;i<=10000000;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
mu[i]=-1;
}
for(int j=1;(long long)i*Prime[j]<=10000000;j++)
{
flag[i*Prime[j]]=true;
if(i%Prime[j]==0)
{
mu[i*Prime[j]]=0;
break;
}
else
mu[i*Prime[j]]=mu[i]*(-1);
}
}
for(int i=1;i<=tot;i++)
{
for(int j=Prime[i];j<=10000000;j+=Prime[i])
F[j]+=mu[j/Prime[i]];
}
for(int i=1;i<=10000000;i++)
sum[i]=sum[i-1]+F[i];
}
int main()
{
Prepare();
int T=read();
while(T--)
{
n=read();m=read();
if(n>m)swap(n,m);
long long Ans=0;
for(int i=1,j;i<=n;i=j+1) //这段666
{
j=min(n/(n/i),m/(m/i));
Ans+=(sum[j]-sum[i-1])*(n/i)*(m/i);
}
printf("%lld\n",Ans);
}
return 0;
}
6.bzoj 2154 Crash的数字表格
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 10000010
#define Mod 20101009
int n,m,tot;
int Prime[N/3],F[N],mu[N];
int sum[N];
bool flag[N];
long long Ans;
void Prepare(int n)
{
mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!flag[i])
{
Prime[++tot]=i;
mu[i]=-1;F[i]=-i;
}
for(int j=1;(long long)i*Prime[j]<=n;j++)
{
flag[i*Prime[j]]=true;
if(i%Prime[j]==0)
{
mu[i*Prime[j]]=0;
break;
}
mu[i*Prime[j]]=mu[i]*(-1);
}
}
for(int i=1;i<=n;i++)
sum[i]=(sum[i-1]+((long long)i*i%Mod*mu[i]))%Mod;
}
long long Cal(int x,int y)
{
long long t1=(long long)(x+1)*x/2%Mod,t2=(long long)(y+1)*y/2;
return t1*(t2%Mod)%Mod;
}
int Get(int x,int y)
{
long long Sum=0;
for(int i=1,j;i<=x;i=j+1)
{
j=min(x/(x/i),y/(y/i));
long long qwer=Cal(x/i,y/i)*(sum[j]-sum[i-1])%Mod;
Sum=(Sum+qwer)%Mod;
}
return (int)Sum;
}
int main()
{
cin>>n>>m;
if(n>m)swap(n,m);
Prepare(m);
for(int i=1,j;i<=n;i=j+1)
{
j=min(n/(n/i),m/(m/i));
long long qwer=(long long)(i+j)*(j-i+1)/2%Mod*Get(n/i,m/i)%Mod;
Ans=(Ans+qwer)%Mod;
}
Ans=(Ans+Mod)%Mod;
cout<<Ans<<endl;
return 0;
}
7⃣️扩展大步小步算法
bzoj 2480 Mod
真是醉了,写了个快速乘比普通的还慢。。tle了找了好久
/**************************************************************
Problem: 2480
User: Edward2173
Language: C++
Result: Accepted
Time:6368 ms
Memory:2604 kb
****************************************************************/
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
using namespace std;
#define N 100010
#define INF 0x3f3f3f3f
typedef long long ll;
int a,b,p;
int len[N];
int GCD(int a,int b)
{
return !b?a:GCD(b,a%b);
}
ll Quick_mul(ll a,ll b)
{
ll base=a,r=0;
while(b)
{
if(b&1)
r=(r+base)%p;
base=(base+base)%p;
b>>=1;
}
return r;
}
ll Quick_pow(int a,int exp)
{
ll base=a,r=1;
while(exp)
{
if(exp&1)
r=r*base%p;
base=base*base%p;
exp>>=1;
}
return r;
}
int work(int a,int b)
{
a%=p;b%=p;
if(!b)return 0;
ll Add=0,tmp=1;
while(1)
{
int qwer=GCD(a,p);
if(b%qwer!=0)
return INF;
if(qwer==1)
break;
tmp=tmp*a/qwer%p;
b/=qwer;p/=qwer;
Add++;
if(tmp==b)
return (int)Add;
}
map<ll,int> Hash;
int Unit=sqrt((double)p+1.0),Ans=INF;
ll now=b;Hash[now]=0;
for(int i=1;i<Unit;i++)
{
now=now*a%p;
Hash[now]=i;
}
ll base=Quick_pow(a,Unit),S_now=tmp;
for(int i=1;i<=Unit+1;i++)
{
S_now=S_now*base%p;
if(Hash.count(S_now))
return i*Unit-Hash[S_now]+(int)Add;
}
return Ans;
}
int main()
{
while(scanf("%d%d%d",&a,&p,&b))
{
if(a==0&&b==0&&p==0)
break;
int qwer=work(a,b);
if(qwer==INF)
printf("No Solution\n");
else printf("%d\n",qwer);
}
return 0;
}
8⃣️斐波那契数列
codeforces 446 C 推下公式就行了
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
#define N 300010
#define Mod 1000000009LL
typedef long long ll;
int n,m;
ll f[N],F[N],G[N],A[N];
ll a[N*4],b[N*4],sum[N*4];
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
void Prepare()
{
G[1]=f[1]=F[0]=F[1]=1;
for(int i=2;i<=300000;i++)
{
f[i]=(f[i-1]+f[i-2])%Mod;
F[i]=(F[i-1]+f[i-1])%Mod;
G[i]=(G[i-1]+f[i])%Mod;
}
}
void Pushup(int i)
{
sum[i]=(sum[i*2]+sum[i*2+1])%Mod;
}
void Change(int i,int len,ll v1,ll v2)
{
a[i]=(a[i]+v1)%Mod;
b[i]=(b[i]+v2)%Mod;
sum[i]=(sum[i]+F[len-1]*v1%Mod+G[len-1]*v2%Mod)%Mod;
}
void Pushdown(int i,int l,int r)
{
if(a[i]==0&&b[i]==0)
return;
int mid=(l+r)/2,len=mid-l+1;
Change(i*2,len,a[i],b[i]);
ll v1=(f[len-1]*a[i]+f[len]*b[i])%Mod,v2=(f[len]*a[i]+f[len+1]*b[i])%Mod;
Change(i*2+1,r-mid,v1,v2);
a[i]=b[i]=0;
}
void Build(int i,int l,int r)
{
if(l==r)
{
a[i]=b[i]=0;sum[i]=A[l];
return;
}
int mid=(l+r)/2;
Build(i*2,l,mid);
Build(i*2+1,mid+1,r);
Pushup(i);
}
void Update(int i,int l,int r,int left,int right,ll v1,ll v2)
{
if(l>=left&&r<=right)
{
Change(i,r-l+1,v1,v2);
return;
}
Pushdown(i,l,r);
int mid=(l+r)/2;
if(left<=mid)
Update(i*2,l,mid,left,right,v1,v2);
if(right>mid)
{
ll t1=v1,t2=v2;
if(left<=mid)
{
int len=mid-max(left,l)+1;
t1=(f[len-1]*v1+f[len]*v2)%Mod;
t2=(f[len]*v1+f[len+1]*v2)%Mod;
}
Update(i*2+1,mid+1,r,left,right,t1,t2);
}
Pushup(i);
}
ll Query(int i,int l,int r,int left,int right)
{
if(l>=left&&r<=right)
{
return sum[i];
}
Pushdown(i,l,r);
int mid=(l+r)/2;
if(right<=mid)
return Query(i*2,l,mid,left,right);
else if(left>mid)
return Query(i*2+1,mid+1,r,left,right);
else
return (Query(i*2,l,mid,left,mid)+Query(i*2+1,mid+1,r,mid+1,right))%Mod;
}
int main()
{
Prepare();
n=read();m=read();
for(int i=1;i<=n;i++)
A[i]=read();
Build(1,1,n);
for(int i=1;i<=m;i++)
{
int kind=read(),x=read(),y=read();
if(kind==1)
Update(1,1,n,x,y,1,1);
else
printf("%lld\n",Query(1,1,n,x,y));
}
return 0;
}