这里的python全是python3的
力求快、准、狠、短
#质数
##试除法判断质数
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
bool is_prime(int n){
if(n<2)return false;
for(int i=2;i<=n/i;i++)//这样写n不会溢出
if(n%i==0)return false;
return true;
}
int main(){
int n;scanf("%d",&n);
while(n--){
int t;scanf("%d",&t);
if(is_prime(t))puts("Yes");
else puts("No");
}
return 0;
}
##试除法分解质因数
----c++版
https://www.acwing.com/problem/content/869/
//n中最多只包含一个大于根号n的质因子
#include<iostream>
#include<algorithm>
using namespace std;
void divide(int n){
for(int i=2;i<=n/i;i++)//把拼成一个数的所有质数从小到大排列,并一个个取出来并计数
if(n%i==0){//i一定是质数
int s=0;
while(n%i==0){
n/=i;
s++;
}
printf("%d %d\n",i, s);
}
if(n>1)printf("%d %d\n",n,1); // 处理唯一一个大于根号n的质因子
}
int main(){
int n;scanf("%d",&n);
while(n--){
int t;scanf("%d",&t);
divide(t);
puts("");
}
return 0;
}
##质数筛
----c++版埃氏筛
o(nloglogn)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int primes[N],cnt;
int st[N];
void get_primes(int n){
if(n<2)return;
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
for(int j=i+i;j<=n;j+=i)st[j]=true;
}
}
}
int main(){
int n;cin>>n;
cnt=0;
get_primes(n);
printf("%d",cnt);
return 0;
}
----c++版线性筛
o(n)
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e6+10;
int primes[N],cnt;
int st[N];
//线性筛,相当于杀掉所有以2为最小质因子的数、以3为最小质因子的数---以x为最小质因子的数
//但整个过程是分开进行的,妙啊,妙啊
//n只会被其最小质因子筛掉
void get_primes(int n){
if(n<2)return;
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
int main(){
int n;cin>>n;
cnt=0;
get_primes(n);
printf("%d",cnt);
return 0;
}
#约数
##试除法求约数
----c++版
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
vector<int> get_dividers(int n){
vector<int>res;
for(int i=1;i<=n/i;i++)
if(n%i==0){
res.push_back(i);
if(i!=n/i)res.push_back(n/i);
}
sort(res.begin(), res.end());
return res;
}
int main(){
int n;cin>>n;
while(n--){
int t;cin>>t;
auto res=get_dividers(t);
for(auto k:res)cout<<k<<' ';
cout<<endl;
}
return 0;
}
##约数个数
基于算数基本定理
有公式的,自行百度
----c++版
#include<iostream>
#include<algorithm>
#include<unordered_map>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
//int范围内的约数最多的数的约数有1650个
int main(){
int n;cin>>n;
unordered_map<int,int>primes;
while(n--){
int x;cin>>x;
for(int i=2;i<=x/i;i++)
while(x%i==0){
x/=i;
primes[i]++;
}
if(x>1)primes[x]++;
}
ll res=1;
for(auto prime:primes)res=res*(prime.second+1)%mod;
cout<<res;
return 0;
}
##约数之和
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
typedef long long ll;
int main(){
int n;cin>>n;
unordered_map<int,int>primes;
while(n--){
int x;cin>>x;
for(int i=2;i<=x/i;i++)
while(x%i==0){
x/=i;
primes[i]++;
}
if(x>1)primes[x]++;
}
ll res=1;
for(auto prime:primes){
int p=prime.first,a=prime.second;
ll t=1;
while(a--)t=(t*p+1)%mod;
res=res*t%mod;
}
cout<<res;
return 0;
}
##最大公约数(欧几里得算法/辗转相除法)
----c++版
#include<iostream>
using namespace std;
int gcd(int a,int b){ //两个gcd约数集合是一样的
return b?gcd(b,a%b):a;//a和0的最大公约数是a
}
int main(){
int n;cin>>n;
while(n--){
int a,b;cin>>a>>b;
cout<<gcd(a,b)<<endl;
}
return 0;
}
#欧拉函数
https://www.acwing.com/problem/content/875/
----c++版
定义法
//Φ(n)表示1-n中与n互质的数的个数, 互质就是gcd=1
//用容斥原理证明公式
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n;cin>>n;
while(n--){
int a;cin>>a;
int res=a;
for(int i=2;i<=a/i;i++)
if(a%i==0){
res=res/i*(i-1);//整数,先除再乘不会越界
while(a%i==0)a/=i;
}
if(a>1)res=res/a*(a-1);
cout<<res<<endl;
}
return 0;
}
##筛法求欧拉函数
----c++版
https://www.acwing.com/problem/content/876/
//求1-n中每一个数的欧拉函数
#include<iostream>
#include<algorithm>
using namespace std;
const int N=1e7+10;
int primes[N],cnt;
int phi[N];
bool st[N];
typedef long long ll; //和最大是n方,会爆int
ll get_eulers(int n){//接用线性筛的模板
phi[1]=1;
for(int i=2;i<=n;i++){
if(!st[i]){
primes[cnt++]=i;
phi[i]=i-1;
}for(int j=0;primes[j]<=n/i;j++){///注意n/i
st[primes[j]*i]=true;
if(i%primes[j]==0){
phi[primes[j]*i]=primes[j]*phi[i];
break;
}
phi[primes[j]*i]=phi[i]*(primes[j]-1);
}
}
ll res=0;
for(int i=1;i<=n;i++)res+=phi[i];
return res;
}
int main(){
int n;cin>>n;
cout<<get_eulers(n)<<endl;
return 0;
}
欧拉定理:若a与n互质,则a的phi(n)次方与n同余1
#快速幂
----c++版
https://www.acwing.com/problem/content/877/
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1)res=(ll)res*a%p;
k>>=1;
a=(ll)a*a%p;//预处理下一个
}
return res;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
int a,k,p;
scanf("%d%d%d",&a,&k,&p);
printf("%d\n",qmi(a,k,p));
}
return 0;
}
##快速幂求逆元
----c++版
https://www.acwing.com/problem/content/878/
//本质上还是求快速幂
//联系费马定理
//有可能无解
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1)res=(ll)res*a%p;
k>>=1;
a=(ll)a*a%p;//预处理下一个
}
return res;
}
int main(){
int n;
scanf("%d",&n);
while(n--){
int a,p;
scanf("%d%d",&a,&p);
int res=qmi(a,p-2,p);
if(a%p)printf("%d\n",res);
else puts("impossible");/无解
}
return 0;
}
#扩展欧几里得算法
裴蜀定理:对任意正整数a、b,那么存在整数x、y使得ax+by等于a和b的最大公约数
----c++版
https://www.acwing.com/problem/content/879/
#include<iostream>
#include<algorithm>
using namespace std;
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d = exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main(){
int n;scanf("%d",&n);
while(n--){
int a,b,x,y;
scanf("%d%d",&a,&b);
exgcd(a,b,x,y);
printf("%d %d\n",x,y);
}
return 0;
}
##线性同余方程
----c++版
https://www.acwing.com/problem/content/880/
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int exgcd(int a,int b,int &x,int &y){
if(!b){
x=1,y=0;
return a;
}
int d = exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
int main(){
int n;scanf("%d",&n);
while(n--){
int a,b,m,x,y;
scanf("%d%d%d",&a,&b,&m);
int d=exgcd(a,m,x,y);
if(b%d)puts("impossible");
else printf("%lld\n",(ll)x*(b/d)%m);
}
return 0;
}
#中国剩余定理
一些基础知识
----c++版
https://www.acwing.com/problem/content/206/
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll exgcd(ll a, ll b, ll &x, ll &y){
if(!b){
x=1;y=0;
return a;
}
ll d=exgcd(b, a%b, y, x);
y-=a/b*x;
return d;
}
int main(){
int n;cin>>n;
bool has_ans=true;
ll a1,m1;
cin>>a1>>m1;
for(int i=0;i<n-1;i++){
ll a2,m2;
cin>>a2>>m2;
ll k1,k2;
ll d=exgcd(a1, a2, k1, k2);
if((m2-m1)%d){
has_ans=false;
break;
}
k1*=(m2-m1)/d;
ll t=a2/d;
k1=(k1%t+t)%t;
m1=a1*k1+m1;
a1=abs(a1/d*a2);
}
if(has_ans){
cout<<(m1%a1+a1)%a1<<endl;
}else{
puts("-1");
}
return 0;
}
#高斯消元法
https://www.acwing.com/problem/content/885/
----c++版
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=110;
const double eps=1e-6;
int n;
double a[N][N];
int gauss(){
int c,r;
for(c=0,r=0;c<n;c++){
int t=r;
for(int i=r;i<n;i++)
if(fabs(a[i][c])>fabs(a[t][c]))
t=i;
if(fabs(a[t][c])<eps)continue;
for(int i=c;i<=n;i++)swap(a[t][i],a[r][i]);//有n+1列
for(int i=n;i>=c;i--)a[r][i]/=a[r][c];
for(int i=r+1;i<n;i++)
if(fabs(a[i][c])>eps)
for(int j=n;j>=c;j--)
a[i][j]-=a[r][j]*a[i][c];//第一个数变成0
r++;
}
if(r<n){
for(int i=r;i<n;i++)
if(fabs(a[i][n])>eps)
return 2;//no solution
return 1;//infinite solutions
}
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
a[i][n]-=a[i][j]*a[j][n];
return 0;//only one
}
int main(){
cin>>n;
for (int i=0;i<n;i++)
for(int j=0;j<n+1;j++)
cin>>a[i][j];
int t=gauss();
if(t==0){
for(int i=0;i<n;i++)printf("%.2lf\n",a[i][n]);
}else if(t==1)puts("Infinite group solutions");
else puts("No solution");
return 0;
}
##解异或线性方程组
https://www.acwing.com/problem/content/886/
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int n;
int a[N][N];
int gauss(){
int r,c;
for(r=c=0;c<n;c++){
int t=r;
for(int i=r;i<n;i++)
if(a[i][c]){
t=i;
break;
}
if(!a[t][c])continue;
for(int i=c;i<=n;i++)swap(a[t][i],a[r][i]);
for(int i=r+1;i<n;i++)
if(a[i][c])
for(int j=c;j<=n;j++)
a[i][j]^=a[r][j];
r++;
}
if(r<n){
for(int i=r;i<n;i++)
if(a[i][n])
return 2;
return 1;
}
for(int i=n-1;i>=0;i--)
for(int j=i+1;j<n;j++)
a[i][n]^=a[i][j]&a[j][n];
return 0;
}
int main(){
cin>>n;
for(int i=0;i<n;i++)
for(int j=0;j<=n;j++)
cin>>a[i][j];
int res=gauss();
if(res==0){
for(int i=0;i<n;i++)cout<<a[i][n]<<endl;
}else if(res==1)puts("Multiple sets of solutions");
else puts("No solution");
return 0;
}
#求组合数
##1 递推形式的
----c++版
https://www.acwing.com/problem/content/887/
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2010,mod=1e9+7;
int c[N][N];
//用预处理的方式
void init(){
for(int i=0;i<N;i++)
for(int j=0;j<=i;j++)
if(!j)c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
int main(){
init();
int n;scanf("%d",&n);
while(n--){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n", c[a][b]);
}
return 0;
}
##2 Cab范围较大的,用预处理出阶乘的方式
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=100010,mod=1e9+7;
int fact[N],infact[N];
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1)res=(ll)res*a%p;
a=(ll)a*a%p;
k>>=1;
}
return res;
}
int main(){
fact[0]=infact[0]=1;
for(int i=1;i<N;i++){
fact[i]=(ll)fact[i-1]*i%mod;
infact[i]=(ll)infact[i-1]*qmi(i,mod-2,mod)%mod;
}
int n;scanf("%d",&n);
while(n--){
int a,b;
scanf("%d%d",&a,&b);
printf("%lld\n",(ll)fact[a]*infact[b]%mod*infact[a-b]%mod);
}
return 0;
}
##3 询问少,Cab比较大,卢卡斯定理
大约O(
)
证明:https://www.cnblogs.com/TY02/p/11813194.html
证明2:
----c++版
https://www.acwing.com/problem/content/889/
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
int p;
int qmi(int a,int k){
int res=1;
while(k){
if(k&1)res=(ll)res*a%p;
a=(ll)a*a%p;
k>>=1;
}
return res;
}
int C(int a,int b){
int res=1;
for(int i=1,j=a;i<=b;i++,j--){
res=(ll)res*j%p;
res=(ll)res*qmi(i,p-2)%p;
}
return res;
}
int lucas(ll a,ll b){
if(a<p&&b<p)return C(a,b);
return (ll)C(a%p,b%p)*lucas(a/p,b/p)%p;
}
int main(){
int n;cin>>n;
while(n--){
ll a,b;
cin>>a>>b>>p;
cout<<lucas(a,b)<<endl;
}
return 0;
}
##4 Cab数大得批爆,需要高精度,先分解质因数
----c++版
https://www.acwing.com/problem/content/890/
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N=5010;
int primes[N],cnt;
bool st[N];
int sum[N];
void get_primes(int n){
for(int i=2;i<=n;i++){
if(!st[i])primes[cnt++]=i;
for(int j=0;primes[j]<=n/i;j++){
st[primes[j]*i]=true;
if(i%primes[j]==0)break;
}
}
}
int get(int n,int p){
int res=0;
while(n){
res+=n/p;
n/=p;
}
return res;
}
vector<int> mul(vector<int>a, int b){
vector<int>c;
int t=0;
for(int i=0;i<a.size();i++){
t+=a[i]*b;
c.push_back(t%10);
t/=10;
}
while(t){
c.push_back(t%10);
t/=10;
}
return c;
}
int main(){
int a,b;cin>>a>>b;
get_primes(a);
for(int i=0;i<cnt;i++){
int p=primes[i];
sum[i]=get(a,p)-get(b,p)-get(a-b,p);
}
vector<int>res;
res.push_back(1);
for(int i=0;i<cnt;i++)
for(int j=0;j<sum[i];j++)
res=mul(res,primes[i]);
for(int i=res.size()-1;i>=0;i--)printf("%d", res[i]);
return 0;
}
##卡特兰数
第18位爆int
477638700
h(0)=h(1)=1
h(n)= h(0)h(n-1)+h(1)h(n-2) + … + h(n-1)h(0) (n>=2)
h(n)=h(n-1)(4*n-2)/(n+1)
h(n)=C(2n,n)/(n+1) (n=0,1,2,…)
h(n)=c(2n,n)-c(2n,n-1) (n=0,1,2,…)
从0,0到6,6有几种方案?
0是向右,1是向上,向右的步数必须时刻大于等于向上的步数
https://www.acwing.com/problem/content/891/
C
a
t
l
a
n
(
n
)
=
C
2
n
n
(
n
+
1
)
Catlan(n) = \frac{C_{2n}^n}{(n+1)}
Catlan(n)=(n+1)C2nn
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int qmi(int a,int k,int p){
int res=1;
while(k){
if(k&1)res=(ll)res*a%p;
a=(ll)a*a%p;
k>>=1;
}
return res;
}
int main(){
int n;cin>>n;
int a=2*n,b=n;
int res=1;
for(int i=a;i>a-b;i--)res=(ll)res*i%mod;
for(int i=1;i<=b;i++)res=(ll)res*qmi(i,mod-2,mod)%mod;
res=(ll)res*qmi(n+1,mod-2,mod)%mod;
cout<<res<<endl;
return 0;
}
#容斥原理
##能被整除的数
集合求并
https://www.acwing.com/problem/content/892/
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=20;
int n,m;
int p[N];
int main(){
cin>>n>>m;
for(int i=0;i<m;i++)cin>>p[i];
int res=0;
for(int i=1;i<1<<m;i++){
int t=1,cnt=0;
for(int j=0;j<m;j++)
if(i>>j&1){
cnt++;
if((ll)t*p[j]>n){
t=-1;
break;
}
t*=p[j];
}
if(t!=-1){
if(cnt%2)res+=n/t;
else res-=n/t;
}
}
cout<<res<<endl;
return 0;
}
#博弈论
##NIM游戏
公平组合游戏 ICG满足:
- 两名玩家交替行动
- 合法行动与玩家无关
- 不能行动的玩家判负
一个公平组合游戏一定可转化为有向图游戏
先手必胜状态:可以走到先手必败态
先手必败状态:只能走到先手必胜态
https://www.acwing.com/problem/content/893/
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n,res=0;
scanf("%d",&n);
while(n--){
int x;scanf("%d",&x);
res^=x;
}
if(res)puts("Yes");
else puts("No");
return 0;
}
##台阶Nim游戏
https://www.acwing.com/problem/content/894/
----c++版
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
int n,res=0;
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d",&x);
if(i%2)res^=x;
}
if(res)puts("Yes");
else puts("No");
return 0;
}
##SG函数
##集合nim游戏
https://www.acwing.com/problem/content/description/895/
----c++版
#include<iostream>
#include<cstring>
#include<algorithm>
#include<unordered_set>
using namespace std;
const int N=110,M=10010;
int n,m;
int s[N],f[M];
int sg(int x){//记忆化搜索保证每个状态只算一次
if(f[x]!=-1)return f[x];
unordered_set<int>S;
for(int i=0;i<m;i++){
int sum=s[i];
if(x>=sum)S.insert(sg(x-sum));
}
for(int i=0;;i++)
if(!S.count(i))
return f[x]=i;
}
int main(){
cin>>m;
for(int i=0;i<m;i++)cin>>s[i];
cin>>n;
memset(f, -1, sizeof f);
int res=0;
for(int i=0;i<n;i++){
int x;
cin>>x;
res ^= sg(x);
}
if(res)puts("Yes");
else puts("No");
return 0;
}
##拆分nim游戏
https://www.acwing.com/problem/content/896/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_set>
using namespace std;
const int N=110;
int f[N];
int sg(int x){
if(f[x]!=-1)return f[x];
unordered_set<int>S;
for(int i=0;i<x;i++)
for(int j=0;j<=i;j++)
S.insert(sg(i)^sg(j));
for(int i=0;;i++)
if(!S.count(i))
return f[x]=i;
}
int main(){
int n;cin>>n;
int res=0;
memset(f, -1, sizeof f);
for(int i=0;i<n;i++){
int x;cin>>x;
res^=sg(x);
}
if(res)puts("Yes");
else puts("No");
return 0;
}