我的模板1.0

0. 头文件

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define fi first
 4 #define se second
 5 #define U unsigned
 6 #define P std::pair<int,int>
 7 #define LL long long
 8 #define pb push_back
 9 #define MP std::make_pair
10 #define V std::vector<int>
11 #define all(x) x.begin(),x.end()
12 #define CLR(i,a) memset(i,a,sizeof(i))
13 #define FOR(i,a,b) for(int i = a;i <= b;++i)
14 #define ROF(i,a,b) for(int i = a;i >= b;--i)
15 #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
16 #define INF 0x3f3f3f3f
17 #define lowbit(x) ((x)&-(x))
18 #define MOD 1000000007
19 #define lson l,mid,rt<<1
20 #define rson mid+1,r,rt<<1|1
21 const int N=1e5+7;

1. 琐碎操作

1.1 结构体

1 struct _node{
2     int id,a,b;
3     bool operator < (const _node k) const{
4         if(a==k.a&&b==k.b) return id>k.id;   //相等的话优先把当前放后面
5         else return a==k.a?b>k.b:a<k.a;  //题目做得越少越塞前面 
6     }
7     _node(int id,int a,int b):id(id),a(a),b(b){}
8 };

1.2 STL

1.2.1 set

性质:set用二叉搜索树实现,集合中的每个元素只出现一次,并且是排好序的。

访问元素的时间复杂度是O(logn),非常高效。

int main(){
    int n,m;scanf("%d%d",&n,&m);
    FOR(i,1,m){
        int x,y;scanf("%d%d",&x,&y);
        if(x==1){
            a[1]++,b[1]+=y;
            if(!s.empty()){
                set<_node>::iterator it=s.lower_bound(_node(1,a[1],b[1]));
                if(s.begin()!=it) s.erase(s.begin(),it); //把前面都干掉 
            }
        }else{
            if(s.find(_node(x,a[x],b[x]))==s.end()){ //查找
                a[x]++,b[x]+=y;
                if(a[x]>a[1]||(a[x]==a[1]&&b[x]<b[1]))
                    s.insert(_node(x,a[x],b[x]));
            }else{
                s.erase(_node(x,a[x],b[x])); // 删除
                a[x]++,b[x]+=y;
                s.insert(_node(x,a[x],b[x])); //插入
            }
        }
        printf("%d
",s.size()+1);
    }
}

1.2.2 vector

去重

sort(all(x)),sort(all(s));
vector<double>::iterator last=unique(all(x));
x.erase(last,x.end());

lower_bound

int l=lower_bound(all(x),s[i].l)-x.begin()+1;
int r=lower_bound(all(x),s[i].r)-x.begin()+1;

1.3 python

t=int(input())
for i in range(t):
    x,y=map(int,input().split())
    c=list(map(int,input().split()))
    
    path1=abs(x)*c[0 if x>=0 else 3]+abs(y-x)*c[1 if y-x>=0 else 4]
    path2=abs(y)*c[0 if y>=0 else 3]+abs(x-y)*c[5 if x-y>=0 else 2]
    path3=abs(y)*c[1 if y>=0 else 4]+abs(x)*c[5 if x>=0 else 2]
    
    print(min(path1,path2,path3))

国王的游戏(贪心)

N=int(input())
s=input().split()
S=int(s[0])
T=int(s[1])
a=[]#一个列表
for i in range(1,N+1):
    k=input().split()
    a.append((int(k[0]),int(k[1])))
a.sort(key=lambda x:x[0]*x[1])
ans=0
for i in range(0,N):
    if(S//(a[i])[1]>ans):
        ans=S//(a[i])[1]
    S*=(a[i])[0]
print(ans)

for _ in range(int(input())):
    a,b=map(int,input().split())
    print(a^b)

读取到end of file:

if __name__ == '__main__':
    while True:
        try:
            # do stuffs of the problem
        except EOFError:   #end of file退出
            break

进制转换:

十->2

n=int(input())
print(bin(n))

2->十

n=input()
print(int(n,2))

1.4 二分查找

int binary_search(int n,int k){
    int low=1,high=n;
    int mid;
    while(low<=high){
        mid=(high+low)>>1;
        if(a[mid]>k)high=mid-1;
        else if(a[mid]==k){
            if(mid!=1){
                while(a[mid]==k){
                    mid--;
                }
                return mid+1;
            }
            else return mid;
        }
        else low=mid+1; 
    }
    return -1;
}

1.5 尺取法

连续+暴力枚举

#include<iostream>
#include<stdio.h>
#include<set>
#include<cstdio>
#include<string.h>
#include<cstdlib>  
#include<stack>  
#include<queue>  
#include<algorithm>  
#include<cstring>  
#include<string>  
#include<cmath>  
#include<vector>  
#include<bitset>  
#include<list>  
#include<sstream>   
#include<map>
#include<functional> 
using namespace std;
const int N=1e5+5;
const int inf=1e9+7;
int a[N];
typedef unsigned long long ull;
int main(){
    ull s;
    int t;
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d%llu",&n,&s);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        deque<int>q;
        q.clear();
        ull sum=0;
        int i=1;
        int len=0,ans=inf;
        while(1){
            while(i<=n&&sum<s){
                sum+=a[i];
                q.push_back(a[i++]);
                len++;
            }
            if(sum<s) break;
            ans=min(ans,len);
            len--;
            sum-=q.front();
            q.pop_front();
        }
        if(ans==inf) printf("0
");
        else printf("%d
",ans);
    }
}

2. 动态规划

2.1 背包DP

#include<bits/stdc++.h>
using namespace std;
const int maxn=10000;
int dp[1003];//前:第几种物品 后:所装多少 
int t[maxn+2],c[maxn+2],p[maxn+2];
int m;//全局变量:总时间(背包容量) 
void completepack(int i,int cost,int weight){
    for(int j=0;j<=m;j++){
        if(j>=cost)dp[j]=max(dp[j],dp[j-cost]+weight);
    }
}
void zeroonepack(int i,int cost,int weight){
    for(int j=m;j>=0;j--){
        if(j>=cost)
        dp[j]=max(dp[j],dp[j-cost]+weight);
    }
}
void multiplepack(int i,int cost,int weight,int amount){
    if(cost*amount>=m){
        completepack(i,cost,weight);
        return;
    }
    int k=1;
    while(k<amount){
        zeroonepack(i,k*cost,k*weight);
        amount-=k;
        k*=2;
    }
    zeroonepack(i,amount*cost,amount*weight);
} 
int main(){
    int h1,m1,h2,m2,n;
    scanf("%d:%d %d:%d %d",&h1,&m1,&h2,&m2,&n);
    for(int i=1;i<=n;i++)scanf("%d%d%d",&t[i],&c[i],&p[i]);
    int mx=m2-m1;
    int hx=(h2-h1)*60;
    if(mx<0)hx=(h2-h1-1)*60;
    if(mx<0)mx=60-m1+m2;
    m=hx+mx;
    for(int i=1;i<=n;i++){
        if(p[i]==0)completepack(i,t[i],c[i]);
        else multiplepack(i,t[i],c[i],p[i]);
    }
    printf("%d
",dp[m]);
}

3. 数学

3.1 置换群

求置换的秩k(P^k=1)

#include<iostream>
#include<stdio.h>
#include<set>
#include<cstdio>
#include<string.h>
#include<cstdlib>  
#include<stack>  
#include<queue>  
#include<algorithm>  
#include<cstring>  
#include<string>  
#include<cmath>  
#include<vector>  
#include<bitset>  
#include<list>  
#include<sstream>   
#include<map>
#include<functional> 
using namespace std;
int a[1004],vis[1004];
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
int lcm(int a,int b){
    return a/gcd(a,b)*b;
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
    }
    int ans=1,tmp;
    for(int i=1;i<=n;++i){
        if(!vis[i]){
            tmp=1;
            vis[i]=1;
            int j=a[i];
            while(!vis[j]){
                vis[j]=1;
                j=a[j];
                ++tmp;
            }
            ans=lcm(ans,tmp); 
        }
    }
    printf("%d
",ans);
}

打表求P^k

#include<iostream>
#include<stdio.h>
#include<set>
#include<cstdio>
#include<string.h>
#include<cstdlib>  
#include<stack>  
#include<queue>  
#include<algorithm>  
#include<cstring>  
#include<string>  
#include<cmath>  
#include<vector>  
#include<bitset>  
#include<list>  
#include<sstream>   
#include<map>
#include<functional> 
using namespace std;
int que[204][204],p[204],key[204];
char ans[204],s[204];
int main(){
    int n;
    while(~scanf("%d",&n)&&n){
        for(int i=1;i<=n;i++){
            scanf("%d",&key[i]);
        }
        memset(que,0,sizeof(que));
        memset(p,0,sizeof(p));
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=n;++i){
            que[0][i]=i;
            p[i]=1;
        }
        for(int i=1;i<=n;++i){
            int k=1;
            while(1){
                que[k][i]=key[que[k-1][i]];
                if(que[k][i]==i) break;
                ++p[i];++k;
            }
        }
        int t;
        while(~scanf("%d",&t)&&t){
            getchar();
            cin.getline(s,sizeof(s));
            int len=strlen(s);
            for(int i=len;i<n;++i) s[i]=' ';
            for(int i=1;i<=n;++i){
                int tt=t%p[i];
                ans[que[tt][i]-1]=s[i-1];
            }
            printf("%s
",ans);
        }
        printf("
");
    }
}

已知P^2的k次幂,求P

#include<cstdio>
const int N=1010;
int a[N],a1[N],a0[N],n,s;
void Getnxt(){
    for(int i=1;i<=n;++i) a0[i]=a1[a1[i]];
    for(int i=1;i<=n;++i) a1[i]=a0[i];
}
bool check(){
    for(int i=1;i<=n;++i) if(a1[i]!=a[i]) return 0;
    return 1;
}
int main(){
    while(~scanf("%d%d",&n,&s)){
        for(int i=1;i<=n;++i) scanf("%d",&a[i]),a1[i]=a[i];
        int len=1;
        for(;;++len){
            Getnxt();
            if(check()) break;
        }
        int u=len-s%len;
        for(int i=1;i<=u;++i) Getnxt();
        for(int i=1;i<=n;++i) printf("%d
",a1[i]); 
    }
}

3.2 容斥原理

3.3 数论

3.3.1 欧拉函数

(1)单个求值:定义:对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目

(2)线性筛:

筛质数的线性筛

void init(){
    for(int i=2;i<maxn;i++){
        if(!vis[i]) pri[cnt++]=i;
        for(int j=0;j<cnt&&1ll*i*pri[j]<maxn;j++){
            vis[i*pri[j]]=1;
            //break是因为这个i被pri[j]与之前的某个i筛过了
            //如果i再与其他质数相乘
            //得到的值早就被这个pri[j]筛过
            if(i%pri[j]==0) break;
        }
    }
}

求欧拉函数的线性筛

void get_phi(int n) {
    phi[1]=1;
    for(int i=2;i<=n;i++)
        if(!phi[i])
            for(int j=i;j<=n;j+=i) {
                if(!phi[j]) phi[j]=j;
                phi[j]=phi[j]/i*(i-1);
              }
}

同时求质数和欧拉函数的线性筛:

void init(){
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            phi[i]=i-1;
            pri[cnt++]=i;
        }
        for(int j=0;j<cnt&&1ll*pri[j]*i<maxn;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j])
                phi[i*pri[j]]=phi[i]*(pri[j]-1);//性质1 
            else {
                phi[i*pri[j]]=phi[i]*pri[j];//性质2 
                break;
            }
        }
    }
}

(3)求前缀和:

(i)线性筛出欧拉函数,老老实实O(n)求前缀和

(ii)杜教筛

(iii)通过莫比乌斯反演来求,要借助莫比乌斯函数,所以已经求出了莫比乌斯函数前缀和时这样做最快。时间复杂度O(n^{frac{2}{3}})

 右边可借由数论分块得出,左边前缀和可借由杜教筛得出。

3.3.2 莫比乌斯函数

 线性筛:

void getMu(){
    mu[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]) p[++tot]=i,mu[i]=-1;
        for(int j=1;j<=tot&&i*p[j]<=n;j++){
            vis[i*p[j]]=1;
            if(i%p[j]==0){
                mu[i*p[j]]=0;
                break;
            }
            mu[i*p[j]]=-mu[i];
        }
    }
}

前缀和筛法:

杜教筛和Min_25筛

杜教筛:

借助数论分块,O(n^{frac{2}{3}})

ll get_large_mu(ll x){
    if(x<n) return sum_mu[x];//预处理(线性筛)计算的
    if(mp_mu.find(x)!=mp_mu.end()) return mp_mu[x];//get_large的时候计算过的
    ll res=1ll;
    for(ll i=2,j;i<=x;i=j+1){//从2开始
        j=x/(x/i);
        res-=get_large_mu(x/i)*(j-(i-1));//数论分块,递归调用
    }
    return mp_mu[x]=res;
}

3.3.3 扩展欧几里得

#include<bits/stdc++.h>
using namespace std;
#define f(x,y,z) for(int x=int(y);x<=int(z);x++)
typedef long long ll;
ll gcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return a;
    }
    ll g=gcd(b,a%b,y,x);//调换x,y
    y-=x*(a/b);//是原处理经过因为调换了xy之后进行的处理
    return g;    
}

int main(){
    ll a,b,c,k;
    scanf("%lld%lld%lld%lld",&a,&b,&c,&k);
    //枚举z的解 
    ll x0,y0;
    ll g=gcd(a,b,x0,y0);
    f(z,0,k/c){
        ll cc=k-c*z;
        //判断是否有整数解:cc是否是a和b的最小公倍数的倍数。
        if(!(cc%g)){
            ll mul=cc/g;
            ll x=mul*x0,y=mul*y0;
            x=(x%(b/g)+(b/g))%(b/g);
            //第一个mod:使得可能为负数的x大于-b/g
            //第二个mod:使得其变为正数
            //第三个mod:使得x为最小正整数(为了让y能大于0) 
            y=(cc-x*a)/b;
            if(x>=0&&y>=0){
                printf("%lld %lld %lld
",x,y,z);
                break;
            }
        } 
    }
}

3.3.4 逆元

求法:

(1)扩展欧几里得(原理:转化为二元一次方程,要求gcd(a,m)=1

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void ex_gcd(ll a,ll b,ll &x,ll &y){
    if(b==0){
        x=1,y=0;
        return ;
    }
    ex_gcd(b,a%b,y,x);
    y-=a/b*x;
}
ll mod_inverse(ll a,ll m){
    ll x,y;
    ex_gcd(a,m,x,y);
    return (m+x%m)%m;//最小正整数解
}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll n,b;
        scanf("%lld%lld",&n,&b);
        ll b_inv=mod_inverse(b,9973);
        printf("%d
",n*b_inv%9973);
    }
}

(2)费马小定理求(要求m为质数)

ll inv(ll a){
    return quickpow(a,mod-2);
}

(3)线性求

ll inv(ll a){
    return a==1?1:(long long)(mod-mod/a)*inv(mod%a)%mod;
}

(4)(批量求法)线性求

void Inverse(int m,int inv[],int n){//线性求<=n的数%m意义下的逆元 
    inv[1]=1;
    for(int i=2;i<=n;i++){
        inv[i]=1ll*(m-m/i)*inv[m%i]%m;
    }
}

3.3.5 数论分块

long long ans = 0;
for (long long l = 1, r; l <= n; l = r + 1) {  //此处l意同i,r意同j,下个计算区间的l应为上个区间的r+1
  if (k / l != 0)
    r = min(k / (k / l), n);
  else
    r = n;  // l大于k时
  ans += (k / l) * (r - l + 1);  
}

3.4 组合数学

3.4.1 求组合数

(1)杨辉三角递推公式

(2)乘法逆元

(3)Lucas 定理

void c1(){     // 杨辉三角
    c[0][0]=1;
    for(int i=1;i<maxn;i++){
        c[i][0]=1;c[i][i]=1;
    }
    for(int i=1;i<maxn;i++){
        for(int j=1;j<=i-1;j++){
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
        }
    }
}

4. 数据结构

4.1 单调栈

对于数组中每个值,求它右边第一个大于它的值的位置与当前位置之间的值的数目。

从右往左单调栈,维护值为降序的位置。

#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<cstdlib>  
#include<stack>    
#include<algorithm>  
#include<cstring>  
#include<string>  
#include<cmath>  
#include<bitset>   
#include<sstream>   
#include<functional>
#define eqfor(i,a,b) for(int i=a;i<=b;++i) 
using namespace std;
typedef long long ll;
stack<ll>s;
ll a[80004];
int main(){
    int n;
    ll ans = 0,x;
    scanf("%d",&n);
    eqfor(i,1,n) scanf("%d",&a[i]);
    for(int i=n;i>=1;--i){
        while(!s.empty()&&a[i]>a[s.top()]) s.pop();
        if(s.empty()) ans += n-i;
        else ans += s.top()-1-i;
        s.push(i);
    }
    printf("%lld
",ans);
}

4.1.2 单调队列

性质:区间最值问题、队列性质

Deque(STL)

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+4;
const int inf=1e9;
int s[N];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        int tmp;
        scanf("%d",&tmp);
        s[i]=s[i-1]+tmp;
    }
    deque<int>q;
    q.push_back(0);
    int ans=-inf;
    for(int i=1;i<=n;i++){
        while(q.size()&&q.front()<i-m)
            q.pop_front();
        while(q.size()&&s[q.back()]>=s[i])
            q.pop_back();
        q.push_back(i);
        ans=max(ans,s[i]-s[q.front()]);
    }
    printf("%d
",ans);
}

5. 字符串

5.1 马拉车

求最长回文子串

string preProcess(int len,string s){
    if(len==0) return "^$";
    string ret="^";
    for(int i=0;i<len;++i)
        ret+="#",ret+=s[i];
    ret+="#$";
    return ret;
}

string manacher(int len,string s){
    string T=preProcess(len,s);
    int n=T.length();
    int C=0,R=0;
    for(int i=1;i<n-1;i++){
        int i_mirror=2*C-i;
        if(R>i) P[i]=min(R-i,P[i_mirror]);// 防止超出 R
        else P[i]=0;// 等于 R 的情况
        // 碰到之前讲的三种情况时候,需要利用中心扩展法
        while(T[i+1+P[i]]==T[i-1-P[i]]) P[i]++;
        // 判断是否需要更新 R
        if(i+P[i]>R) C=i,R=i+P[i];
    }
    // 找出 P 的最大值
    int maxLen=0,centerIndex=0;
    for(int i=1;i<n-1;i++)
        if(ed==len&&P[i]>maxLen) maxLen=P[i],centerIndex=i;
    //最开始讲的求原字符串下标
    int st=(centerIndex-maxLen)/2,ed=st+maxLen;
    return s.substr(start,start+maxLen);
}

5.3 AC自动机

#include<bits/stdc++.h>
using namespace std;
const int SZ=500003;
const int N=1000003;
namespace AC{
    int tr[SZ][26],tot;
    int e[SZ],fail[SZ];
    void init(){
        memset(tr,0,sizeof(tr));
        memset(e,0,sizeof(e));
        memset(fail,0,sizeof(fail));
        tot=0;
    }
    void insert(char *s){
        int u=0;
        for(int i=1;s[i];i++){
            if(!tr[u][s[i]-'a']) tr[u][s[i]-'a']=++tot;
            u=tr[u][s[i]-'a'];
        }
        e[u]++;
    }
    queue<int>q;
    void build(){
        for(int i=0;i<26;i++)
            if(tr[0][i]) q.push(tr[0][i]);
        while(q.size()){
            int u=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(tr[u][i])
                    fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
                else
                    tr[u][i]=tr[fail[u]][i];
            }
        }
    }
    int query(char *t){
        int u=0,res=0;
        for(int i=1;t[i];i++){
            u=tr[u][t[i]-'a'];
            for(int j=u;j&&e[j]!=-1;j=fail[j])
                res+=e[j],e[j]=-1;
        }
        return res;
    }
}

char s[N];int n,ca;
int main(){
    scanf("%d",&ca);
    while(ca--){
        scanf("%d",&n);
        AC::init();
        for(int i=1;i<=n;i++) scanf("%s",s+1),AC::insert(s);
        scanf("%s",s+1);
        AC::build();
        printf("%d
",AC::query(s));
    }
}

5.4 哈希

void init(){
    base[0]=1;
    for(int i=1;i<N;i++)
        base[i]=base[i-1]*seed; 
}
void makehash(int len){
    for(int i=1;i<=len;i++)
        _hash[i]=_hash[i-1]*seed+(s[i]-'a'+1);
}

取子串的hash:

ull gethash(int i,int l){
    return _hash[i+l-1]-_hash[i-1]*base[l];
}
原文地址:https://www.cnblogs.com/rainartist/p/13905351.html