• 我的模板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];
    }
  • 相关阅读:
    Leetcode: Summary Ranges
    Leetcode: Kth Smallest Element in a BST
    Leetcode: Basic Calculator II
    Leetcode: Basic Calculator
    Leetcode: Count Complete Tree Nodes
    Leetcode: Implement Stack using Queues
    Leetcode: Maximal Square
    Leetcode: Contains Duplicate III
    Leetcode: Invert Binary Tree
    Leetcode: The Skyline Problem
  • 原文地址:https://www.cnblogs.com/rainartist/p/13905351.html
Copyright © 2020-2023  润新知