ACM常用模板 ver1.0

ACM模板(临时)

ver1.0,待更新

一.数据结构

KMP
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int ne[N];
string s1,s2;
int len1 ,len2;
void init(){
    int ix1 = 0,ix2= -1;
    ne[0] = -1;
    while(ix1<len1){
        if(ix2==-1||s1[ix2]==s1[ix1]){
            ne[++ix1]=++ix2;
        }
        else ix2 = ne[ix2]; 
    }
}
void KMP(){
    int ix1 = 0,ix2 =0;
    while(ix1<len2){
        if(ix2==-1||s2[ix1]==s1[ix2]) ix1++,ix2++;
        else ix2 = ne[ix2];
        if(ix2 == len1){
            cout<< ix1-len1<<" " ;
        }
    }
}
int main(){
    int n;
    cin>>n>>s1>>n>>s2;
    len1 = s1.length();
    len2 = s2.length();
    init();
    KMP();
    return 0;
}
Trie 树
const int N = 1e6+7;
int son[N][26],cnt[N],idx=0;
void insert(string str){
    int p = 0;
    for(int i = 0;str[i];i++){
        int u = str[i] - 'a';
        if(!son[p][u]) son[p][u] = ++idx;
        p = son[p][u];
    }
    cnt[p]++;
}
int query(string str){
    int p = 0;
    for(int i = 0;str[i];i++){
        int u = str[i] - 'a';
        if(!son[p][u]) return 0;
        p = son[p][u];
    }
    return cnt[p];
}
带权并查集
食物链

动物王国中有三类动物 A,B,C,A 吃 B,B 吃 C,C 吃 A。现有 N 个动物,以 1∼N 编号。

每个动物都是 A,B,C 中的一种,但是我们并不知道它到底是哪一种。

第一种说法是 1 X Y,表示 X 和 Y 是同类。

第二种说法是 2 X Y,表示 X 吃 Y。

此人对 N 个动物,用上述两种说法,一句接一句地说出 K 句话,这 K 句话有的是真的,有的是假的。

当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

当前的话与前面的某些真的话冲突,就是假话;
当前的话中 X 或 Y 比 N 大,就是假话;
当前的话表示 X 吃 X,就是假话。
你的任务是根据给定的 N 和 K 句话,输出假话的总数。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
int A[N],d[N];
int find(int x){
    if(A[x]!=x) {
        int t = find(A[x]);
        d[x] += d[A[x]];
        A[x] = t; 
    }
    return A[x]; 
}
int main(){
    int n,m;
    cin>>n>>m;
    for(int i = 1;i<=n;i++) A[i] = i;
    int res = 0;
    for(int i = 1;i<=m;i++){
        int t,x,y;
        cin>>t>>x>>y;
        int px = find(x),py = find(y);
        if(x>n||y>n) res++;
        else {
            if(t==1) {
                if(px==py&&(d[x]-d[y])%3)res++;
                else if(px!=py){
                    A[px] =py;
                    d[px] = d[y]-d[x];
                }
            }
            else {
                if(px==py&&(d[x]-d[y]-1)%3) res++;
                else if(px!=py){
                    A[px] = py;
                    d[px] = d[y]-d[x]+1;
                }
            }
        }
    } 
    cout<<res<<endl;
    return 0;
}
字符串哈希
841. 字符串哈希

给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2] 这两个区间所包含的字符串子串是否完全相同。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
typedef unsigned long long ull;
const int I = 131;
ull p[N]={1},h[N],n,q;
char s[N]; 
ull check(int l,int r){
    return h[r]-h[l-1]*p[r-l+1];
}
int main(){
    scanf("%d%d%s",&n,&q,s+1); 
    for(int i = 1;i<=n;i++){
        p[i] = p[i-1]*I;
        h[i] = I*h[i-1] + s[i];
    }
    while(q--){
        int l,r,ll,rr;
        cin>>l>>r>>ll>>rr;
        if(check(l,r)==check(ll,rr)) cout<<"Yes"<<endl;
        else cout<<"No\n";  
    }
    return 0;
}

线段树
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+7;
typedef long long ll;
ll A[N];
ll n,m,p;
struct TREE{
	ll val,lazy=0,mul=1;
}tree[N*4];
void pushup(ll rt){
	tree[rt].val = (tree[rt*2].val+tree[rt*2+1].val)%p;
} 
void build(ll l,ll r,ll rt){
	if(l==r) {
		tree[rt].val = A[l];
		return ;
	}
	ll mid = (l+r)/2;
	build(l,mid,rt*2);build(mid+1,r,rt*2+1);
	pushup(rt);
}
void pushdown(ll l,ll r,ll rt){
	tree[rt*2].val = (tree[rt].mul*tree[rt*2].val+tree[rt].lazy*l)%p;
	tree[rt*2+1].val = (tree[rt].mul*tree[rt*2+1].val+tree[rt].lazy*r)%p;
	tree[rt*2].mul = (tree[rt].mul*tree[rt*2].mul)%p;
	tree[rt*2+1].mul = (tree[rt].mul*tree[rt*2+1].mul)%p;
	tree[rt*2].lazy =  (tree[rt*2].lazy*tree[rt].mul+tree[rt].lazy)%p;
	tree[rt*2+1].lazy =  (tree[rt*2+1].lazy*tree[rt].mul+tree[rt].lazy)%p;
	tree[rt].lazy = 0;
	tree[rt].mul = 1;	
}
void updata1(ll L,ll R,ll C,ll l,ll r,ll rt){
	if(l>=L&&r<=R){
		tree[rt].lazy = (C+tree[rt].lazy)%p;
		tree[rt].val = (tree[rt].val+C*(r-l+1))%p;
		return;
	} 	
	ll mid = (l+r)/2;
	pushdown(mid-l+1,r-mid,rt);
	if(mid>=L) updata1(L,R,C,l,mid,rt*2);
	if(mid<R) updata1(L,R,C,mid+1,r,rt*2+1);
	pushup(rt); 
}
void updata2(ll L,ll R,ll C,ll l,ll r,ll rt){
	if(l>=L&&r<=R){
		tree[rt].lazy = tree[rt].lazy*C%p;
		tree[rt].mul = tree[rt].mul*C%p;
		tree[rt].val = (tree[rt].val*C)%p;
		return;
	} 	
	ll mid = (l+r)/2;
	pushdown(mid-l+1,r-mid,rt);
	if(mid>=L) updata2(L,R,C,l,mid,rt*2);
	if(mid<R) updata2(L,R,C,mid+1,r,rt*2+1);
	pushup(rt); 
}
ll ask(ll L,ll R,ll l,ll r,ll rt){
	if(l>=L&&r<=R){
		return tree[rt].val%p;
	} 	
	ll mid = (l+r)/2;
	if(l>R||r<L)return 0;
	pushdown(mid-l+1,r-mid,rt);
	return (ask(L,R,l,mid,rt*2)+ask(L,R,mid+1,r,rt*2+1))%p;
}

int main(){
	cin>>n>>p;
	for(ll i = 1;i<=n;i++){
		cin>>A[i];
	}
	cin>>m;
	build(1,n,1);
	while(m--){
		ll x,y,a,c;
		cin>>a>>x>>y;
		if(a==1) {
			cin>>c;
			updata2(x,y,c,1,n,1);
		}
		else if(a==2){
			cin>>c;
			updata1(x,y,c,1,n,1);
		}
		else cout<<ask(x,y,1,n,1)%p<<'\n';
	}
	return 0;
}

二.数学

欧拉函数

求单个

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+7;
int main(){
    int T;
    cin>>T;
    while(T--){
        ll x;
        cin>>x;
        ll res = x;
        for(ll i = 2;i<=x/i;i++){
            if(x%i==0){
                while(x%i==0) x/=i;
                res = res/i*(i-1); 
            }
        }
        if(x>1) res = res/x*(x-1);
        cout<<res<<endl;
    }
    return 0;
}

线性求

void 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++)
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)
            {
                phi[primes[j] * i] = phi[i] * primes[j]; 
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);
        }
    }
}
求逆元

1.费马小定理 inv[i] = pow(i,p-2) p为质数
2.exgcd

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 -= x*(a/b);
	return d;
}

3 . 线性递推

void init(){
	inv[1] = 1;
	for(int i = 2;i <= N;i++){
	inv[i] = (p - p / i) * inv[p % i] % p;
	}
} 
组合数
  1. 递推
void init(){
    for(int i=0;i<4000;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;
        }
    }
}

2.公式 Cba=a!/b!(a−b)!=a!∗b!−1∗(a−b)!−1
即求(b!)逆元和(a-b)!-1的逆元,递推即可
3.卢卡斯公式

int quick_power(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 C(int a, int b, int p)
{
    if (b > a) {
        return 0;
    }
    int res = 1;
    for (int i = 1, j = a; i <= b; i++, j--) {
        res = (ll)res * j % p;
        res = (ll)res * quick_power(i, p - 2, p) % p;
    }
    return res;
}
int lucas(ll a, ll b, int p)//a个里面调b个
{
    if (a < p && b < p) {
        return C(a, b, p);
    }
    return (ll)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}
矩阵加速

斐波那契求和

#include<bits/stdc++.h>
using namespace std;
const int N = 3;
typedef long long ll;
ll n,m;
ll A[N][N] =    // 上述矩阵 A
{
    {2, 0, -1},
    {1, 0, 0},
    {0, 1, 0}
};
ll S[N] = {2,1,0};
void cal(ll A[][N],ll B[][N]){
    ll nw[N][N]={0};
    for(ll i = 0;i<N;i++){
        for(ll j = 0;j<N;j++){
            for(ll k = 0;k<N;k++){
                nw[i][j] += A[i][k]*B[k][j]%m;
            }
        }
    }
    for(ll i = 0;i<N;i++){
        for(ll j = 0;j<N;j++){
            A[i][j] = nw[i][j]%m;
        }
    } 
}
void cal(ll A[],ll B[][N]){
    ll nw[N] = {0};
    for(ll i = 0;i<N;i++){
        for(ll j = 0;j<N;j++){
            nw[i] += A[j]*B[i][j]%m;
        }
    }
    for(ll i = 0;i<N;i++){
        A[i] = nw[i] % m;
    }
}
int  main(){
    cin>>n>>m;
    while(n){
        if(n&1){
            cal(S,A);
        }
        cal(A,A);
        n>>=1; 
    }
    cout<<((S[2]%m+m)%m)<<endl;
    return 0;
}
三.基础算法
RMQ
ll A[N];
ll n;
ll fa[N][30];
int main(){
    cin>>n;
    for(int i = 1;i<=n;i++){
        cin>>A[i];
        fa[i][0] = A[i];
    }
    for(int i = 1;i<25;i++){
        for(int j = 1;(1<<(i-1))+j<=n;j++){
            fa[j][i] = max(fa[j][i-1],fa[j+(1<<(i-1))][i-1]);
        }
    }
    int m;
    cin>>m;
    while(m--){
        ll x,y;
        cin>>x>>y;
        int t=log2(y-x+1);
        cout<<max(fa[x][t],fa[y-(1<<t)+1][t])<<endl;
    }
    return 0;
}
高精度
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7;
vector<int> A(N),B(N),C(N);
string s,s2;
int len ,len2;
void input(vector<int > A,int ix){
    if(ix<0) cout<<"0";
    for(int i = ix;i>=0;i--)  
     cout<<A[i]; 
    cout<<endl;
}
bool cmp(vector<int > A,vector<int > B){
    if(len!=len2) return len>len2;
    else {
        for(int i = len-1;i>=0;i--){
            if(A[i]>B[i]) return 1;
            if(A[i]<B[i]) return 0; 
        }
    }
    return 1;
}
void add(){
    int s = 0,i;
    for( i = 0;i<=max(len,len2)+1;i++){
        A[i] = s+A[i]+B[i];
        s = A[i]/10;
        A[i]%=10;
    }
    while(!A[i])i--;
    input(A,i);
}
void sub(){
    int s = 0,i;
    if(cmp(A,B)==0) { C = B;
    B = A;
    A = C; 
    cout<<"-"; 
    }
    for( i = 0;i<max(len,len2);i++){
        if(A[i]-B[i]-s<0) A[i] = (A[i]-s+10-B[i]),s=1;
        else A[i]= A[i]-s-B[i],s=0;
    }
    while(!A[i])i--;
    input(A,i);
} 
void mul(){
    for(int i = 0;i<len;i++){
        for(int j = 0;j<len2;j++){
            C[i+j] += A[i]*B[j];
            C[i+j+1] += C[i+j]/10;
            C[i+j]%=10;  
        }
    }
    int k = len+len2;
    while(!C[k]&&k>0) k--;
    input(C,k);
}
int main(){
    cin>>s>>s2;
    len = s.length();
    len2 = s2.length();
    A.resize(N),B.resize(N),C.resize(N);
    for(int i = len-1,k=0;i>=0;i--,k++) A[k] = s[i]-'0';
    for(int i = len2-1,k=0;i>=0;i--,k++) B[k] = s2[i]-'0';
    return 0;
}
离散化
int C[MAXN], L[MAXN];
// 在main函数中...
memcpy(C, A, sizeof(A)); // 复制
sort(C, C + n); // 排序
int l = unique(C, C + n) - C; // 去重
for (int i = 0; i < n; ++i)
    L[i] = lower_bound(C, C + l, A[i]) - C + 1; // 查找
__int128 手写输入输出
__int128 read(){
	__int128 res = 0;
	int sign = 1;
	char ch;
	if((ch=getchar())=='-1') sign = -1;
	else res = res*10 + ch-'0';
	while((ch=getchar())>='0'&&ch<='9'){
		res = res*10 + ch-'0';
	}
	res *= sign;
	return res;
} 
void print(__int128 x ){
	if(x<0){
		x = -x;
		printf("-");
	}
	if(x>9) print(x/10);
	putchar(x%10 + '0');
}
二分

1答案的最大值,[l, r]划分成[l, mid]和[mid + 1, r]

int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}

2.答案的最小值,[l, r]划分成[l, mid - 1]和[mid, r]

int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

四.DP

数位DP
int dp[2000][10],A[N]; 
long long dfs(int pos ,int limit,int lead,int pre){
    long long ans = 0;
    if(pos<0) return 1;
    if(!limit&&!lead&&dp[pos][pre]!=-1) return dp[pos][pre];
    int up = limit?A[pos]:9;
    for(int i = 0;i<=up;i++){
        if(lead||abs(pre-i)>=2) ans+=dfs(pos-1,limit&&i==up,lead&&i==0,i);
    }
    if(!limit&&!lead) dp[pos][pre] = ans;
    return ans;
}
long long slove(long long x){
    int pos = 0;
    memset(dp,-1,sizeof(dp));
    while(x){
        A[pos++] = x%10;
        x/=10;
    } 
    return dfs(pos-1,1,1,-2);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值