线性筛法:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
#define MAXL 1299710
int prime[MAXN];
int check[MAXL];
int tot = 0;
void solve_prime()
{
memset(check, 0, sizeof(check));
for (int i = 2; i < MAXL; ++i)
{
if(!check[i])
prime[tot++] = i;
for (int j = 0; j < tot; ++j)
{
if (i * prime[j] > MAXL)
break;
check[i*prime[j]] = 1;
if (i % prime[j] == 0)
break;
}
}
}
快速幂取模:
typedef long long ll;
ll powerMod(ll x, ll n, ll mod)
{
ll ans = 1;
while (n > 0){
if (n & 1)
ans = (ans * x) % mod;
x = (x * x) % mod;
n >>= 1;
}
return ans;
}
矩阵快速幂:
// 矩阵快速幂Sn=11*Sn-1-10*Sn-2+a,注意运算溢出的问题
#include<bits/stdc++.h>
using namespace std;
int mod;
typedef struct mat
{
int m[3][3];
}mat;
mat mul(mat a,mat b)
{
mat t;
memset(t.m,0,sizeof(t.m));
for(int i=0;i<3;i++)
for(int j=0;j<3;j++)
for(int k=0;k<3;k++)
t.m[i][j]=((long long)t.m[i][j]+(long long)a.m[i][k]*b.m[k][j]+mod)%mod;
return t;
}
mat pow_(mat a,int n)
{
mat b;
memset(b.m,0,sizeof(b.m));
for(int i=0;i<3;i++) b.m[i][i]=1;
while(n>0)
{
if(n&1) b=mul(b,a);
a=mul(a,a);
n>>=1;
}
return b;
}
int main()
{
int a,n;
while(scanf("%d%d%d",&a,&n,&mod)==3){
mat ans;
ans.m[0][0]=11,ans.m[0][1]=-10,ans.m[0][2]=a;
ans.m[1][0]=1,ans.m[1][1]=0,ans.m[1][2]=0;
ans.m[2][0]=0,ans.m[2][1]=0,ans.m[2][2]=1;
ans=pow_(ans,n-1);
printf("%d\n",(ans.m[0][0]*a+ans.m[0][2]+mod)%mod);
}
}
组合数取模:
ll qpow(ll n, ll m, ll p)
{
ll res=1;
while(m)
{
if(m%2!=0)
{
res*=n;
res%=p;
}
n*=n;
n%=p;
m/=2;
}
return res;
}
ll C(ll n,ll m,ll p)
{
if(m>n)
return 0;
ll a=1,b=1;
while(m)
{
a*=n;
a%=p;
n--;
b*=m;
m--;
b%=p;
}
return a*qpow(b,p-2,p)%p;
}
ll Lucas(ll n,ll m,ll p) // C(n,m)%p
{
if(m==0)
return 1;
return Lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
并查集:
const int maxn=1e5+5;
int father[maxn];
void makeSet()
{
for(int i=0;i<maxn;i++)
father[i] = i;
}
int findRoot(int x)
{
int root = x;
while (root != father[root])
{
root = father[root];
}
// 路径压缩,优化
while (x != root)
{
int tmp = father[x];
father[x] = root;
x = tmp;
}
return root;
}
void Union(int x,int y)
{
int a, b;
a = findRoot(x);
b = findRoot(y);
father[a] = b;
}
KMP:
void getNext(string short_string)
{
int len = short_string.size();
int k = -1,j = 0;
Next[0] = k;
while (j < len)
{
if(k == -1 || short_string[k] == short_string[j])
{
j++,k++;
if (short_string[j] == short_string[k])
{
Next[j] = Next[k];
}
else
{
Next[j] = k;
}
}
else
k = Next[k];
}
}
int kmp(string short_string,string long_string)
{
int ans = 0;
int len = long_string.size();
int j = 0,i = 0;
while (i < len)
{
if (j == -1 || long_string[i] == short_string[j])
{
i++,j++;
if (j >= short_string.size()) //如果只匹配一次,直接break
{
ans++;
j = Next[j];
}
}
else
{
j = Next[j];
}
}
return ans;
}
欧拉函数:
int euler_phi(int n){ //单个值
int m = (int)sqrt(n + 0.5);
int ans = n;
for (int i = 2;i <= m;i++){
if (n%i == 0){ //如果存在素因子
ans = ans/i*(i-1);
while (n%i == 0) n/=i;
}
}
if(n > 1) ans = ans/n*(n-1); //考虑n本身
return ans;
}
void phi_table(int n,int *phi){ //欧拉表
for (int i = 1;i <= n;i++) phi[i] = i;
for(int i = 2;i <= n;i++){
if(phi[i] == i){ //类似于Eratosthenes筛法这里
for(int j = i;j <= n;j+=i){
phi[j] = phi[j]/i*(i-1);
}
}
}
}
扩展欧几里得:
ll gcd(ll a,ll b) {
return b == 0 ? a : gcd(b, a % b);
}
求x在模为mod时的逆元:
exgcd(x,mod,x,y)
求出后,第三个参数就是逆元。
mod可以不为质数
void exgcd(ll a, ll b, ll &d, ll &x, ll &y) {
if(!b) d=a,x=1,y=0;
else exgcd(b, a % b, d, y, x),y -= x * (a / b);
}
树状数组:
/*
单点更新,区间查询,(也可区间更新加),逆序对等等
*/
int lowerbit(int x) {
return x & -x;
}
void add(int p, int x) {
while (p < maxn) {
d[p] += x;
p += lowerbit(p);
}
}
int sum(int p) {
int res = 0;
while (p) {
res += d[p];
p -= lowerbit(p);
}
return res;
}
最小生成树:
// 紫书上的Kruskal算法模板
#include<bits/stdc++.h>
using namespace std;
const int maxn=50*99+2;
int n,m,u[maxn],v[maxn],w[maxn],p[maxn],r[maxn];
bool cmp(const int i,const int j)//间接排序函数
{
return w[i]<w[j];//排序的关键字是对象的代号,而不是对象本身
}
int Find(int x)
{
while(x!=p[x]) x=p[x];
return x;
}
int Kruskal()
{
int ans=0;
for(int i=1;i<=n;i++) p[i]=i;//初始化并查集
for(int i=1;i<=m;i++) r[i]=i;//初始化序号
sort(r+1,r+m+1,cmp);//给边排序
for(int i=1;i<=m;i++)
{
int e=r[i];
int x=Find(u[e]),y=Find(v[e]);//找出当前边两个端点所在的集合编号
if(x!=y) ans+=w[e],p[x]=y;//如果在不同集合,合并
}
return ans;
}
int main()
{
while(scanf("%d",&n)==1&&n)
{
m=n*(n-1)/2;
for(int i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]);
printf("%d\n",Kruskal());
}
return 0;
}
最短路:
// Dijkstra算法
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn = 2e5 + 5;
const ll INF = 1e18;
int n,m,k,a,b,c;
struct EGE{int to;ll w;int k;
bool operator < (const EGE& x) const{
return w > x.w;
}
};
vector<EGE> g[maxn];
ll dis[maxn][10];
ll dijkstra(int s){
priority_queue<EGE> q;
q.push({s,0,0});
for(int i=1;i<=n;i++)
for(int j=0;j<=k;j++) dis[i][j] = INF;
dis[1][0] = 0;
while(!q.empty()){
EGE now = q.top();q.pop();
int u = now.to;
int tim = now.k;
ll w = now.w;
if(w > dis[u][tim]) continue;
if(u == n) return w;
for(int i=0;i<g[u].size();i++){
int v = g[u][i].to;
if(dis[v][tim] > w + g[u][i].w){
dis[v][tim] = w + g[u][i].w;
q.push({v,dis[v][tim],tim});
}
if(dis[v][tim+1] > w + 1 && tim+1 <= k){
dis[v][tim+1] = w + 1;
q.push({v,dis[v][tim+1],tim+1});
}
}
}
return 0;
}
int main()
{
scanf("%d %d %d",&n,&m,&k);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&a,&b,&c);
g[a].push_back({b,c,0});
g[b].push_back({a,c,0});
}
cout << dijkstra(1);
return 0;
}
欧拉回路+并查集+字典树:
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5;
int color=0,degree[maxn+1]={0},fa[maxn+1];
struct node
{
bool flag;
int id;
node* next[27];
node()
{
flag=false;
id=0;
memset(next,0,sizeof(next));
}
}root;
int Find(int x)
{
while(x!=fa[x]) x=fa[x];
return x;
}
void mer(int a,int b)
{
int pa=Find(a);
int pb=Find(b);
fa[pb]=pa;
}
int Hash(char *s)
{
node* p=&root;
int len=0;
while(s[len]!='\0')
{
int index=s[len++]-'a';
if(!p->next[index]) p->next[index]=new node;
p=p->next[index];
}
if(p->flag) return p->id;
else
{
p->flag=true;
p->id=++color;
return p->id;
}
}
int main()
{
char a[11],b[11];
for(int i=1;i<=maxn;i++) fa[i]=i;
while(~scanf("%s%s",a,b))
{
int i=Hash(a);
int j=Hash(b);
degree[i]++;
degree[j]++;
mer(i,j);
}
int Root=Find(1);
int cnt=0;
for(int i=1;i<=color;i++)
{
if(degree[i]&1) cnt++;
if(cnt>2||Find(i)!=Root)
{
printf("Impossible\n");
return 0;
}
}
printf("%s\n",cnt==1?"Impossible":"Possible");
}
线段树:
#include<bits/stdc++.h>
using namespace std;
#define INF 0x7fffffff
typedef long long ll;
typedef pair<int,int> P;
const int maxnode=1<<17;
int n,m;
//编号从1到n
int _min,_max,_sum;//全局变量,目前位置的最小值、最大值以及累加和
int op,qL,qR,v;
//m个操作
//1 L R v
//2 L R
struct IntervalTree
{
int sumv[maxnode],minv[maxnode],maxv[maxnode],addv[maxnode];
//维护信息
//维护结点o,它对应的区间是[L,R]
void maintain(int o,int L,int R){
int lc=2*o,rc=2*o+1;
sumv[o]=minv[o]=maxv[o]=0;
if(R>L){
//考虑左右子树
sumv[o]=sumv[lc]+sumv[rc];
minv[o]=min(minv[lc],minv[rc]);
maxv[o]=max(maxv[lc],maxv[rc]);
}
//考虑add操作
minv[o]+=addv[o];
maxv[o]+=addv[o];
sumv[o]+=addv[o]*(R-L+1);
}
//修改操作
void update(int o,int L,int R){
int lc=2*o,rc=2*o+1;
if(qL<=L&&R<=qR){
//递归边界
addv[o]+=v;//累加边界的add值
}
else{
int M=L+(R-L)/2;
if(qL<=M) update(lc,L,M);
if(qR>M) update(rc,M+1,R);
}
//递归结束前重新计算本结点的附加信息
maintain(o,L,R);
}
void query(int o,int L,int R,int add){
if(qL<=L&&R<=qR){
//递归边界:用边界区间的附加信息更新答案
_sum+=sumv[o]+add*(R-L+1);
_min=min(_min,minv[o]+add);
_max=max(_max,maxv[o]+add);
}
else{
//不递归统计,累加参数add
int M=L+(R-L)/2;
if(qL<=M) query(2*o,L,M,add+addv[o]);
if(qR>M) query(2*o+1,M+1,R,add+addv[o]);
}
}
};
IntervalTree tree;
int main()
{
while(scanf("%d%d",&n,&m)==2){
memset(&tree,0,sizeof(tree));
while(m--){
scanf("%d%d%d",&op,&qL,&qR);
if(op==1){
scanf("%d",&v);
tree.update(1,1,n);
}
else{
_sum=0,_min=INF,_max=-INF;
tree.query(1,1,n,0);
printf("%d %d %d\n",_sum,_min,_max);
}
}
}
return 0;
}
容斥原理+莫比乌斯函数:
const int N=1000005;
bool check[N+5];
int prime[N+5];
int phi[N+5];
int mu[N+5];
void miu()
{
memset(check,false,sizeof(check));
mu[1]=1;
int tot=0;
for(int i=2;i<=N;i++)
{
if(!check[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0;j<tot;j++)
{
if(i*prime[j]>N) break;
check[i*prime[j]]=true;
if(i%prime[j]==0)
{
mu[i*prime[j]]=0;
break;
}
else
mu[i*prime[j]]=-mu[i];
}
}
}
int main()
{
miu();
int t;
scanf("%d",&t);
while(t--)
{
LL n;
scanf("%lld",&n);
LL ans=0;
for(LL i=1;i<N&&i*i<=n;i++)
{
LL temp=n/(LL)(i*i);
ans+=mu[i]*temp;
}
printf("%lld\n",ans);
}
return 0;
}