zoukankan      html  css  js  c++  java
  • CSP/NOIP 之前还需要学/复习的东西

    主要是复习。

    当然可能能会发现自己之前学假了然后重学的。

    图论类

    • 割点
    void tarjan(int u,int fa){
      vis[u]=1;int chi=0;//统计孩子数量
      dfn[u]=low[u]=++cnt;
      for(int i=head[u];i;i=e[i].nxt){
        int to=e[i].to;
        if(!vis[to]){
          chi++;tarjan(to,u);
          low[u]=min(low[to],low[u]);
          if(fa!=u&&low[to]>=dfn[u]&&!flag[u]){//第一个依据
    	flag[u]=1;
    	res++;//割点数量
          }
        }
        else if(to!=fa)
        low[u]=min(low[u],dfn[to]);
      }
      if(fa==u&&chi>=2&&!flag[u]){//第二个依据
        flag[u]=1;res++;
      }
    }
    
    void tarjan(int u,int fat){
      fa[u]=fat;
      low[u]=dfn[u]=++cnt;
      for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].to;
        if(!dfn[v]){
          tarjan(v,u);low[u]=min(low[u],low[v]);
          if(low[v]>dfn[u]){vis[v]=true;++bri;}//bri 是割边的数量
        } 
        else if(dfn[v]<dfn[u]&&v!=fat) 
        low[u]=min(low[u],dfn[v]);
      }
    }
    

    数据结构类

    • 哈夫曼树
    struct node{
      int w,h;
      bool operator < (const node &a) const{
        return  a.w==w?h>a.h:w>a.w;
      }  
    };
    
    signed main(){
      n=read();k=read();
      priority_queue<node> q;
      for(int i=1,w;i<=n;i++)
        w=read(),q.push((node){w,1});
      while((q.size()-1)%(k-1))
        q.push((node){0,1});
      while(q.size()>=k){
        int h=-1,w=0;
        for(int i=1;i<=k;i++){
          node t=q.top();q.pop();
          h=max(h,t.h);w+=t.w;
        }
        ans+=w;
        q.push((node){w,h+1});
      }
      printf("%lld
    %lld
    ",ans,q.top().h-1);
      return 0;
    }
    
    • 左偏树
    namespace LIT{
      #define ls lson[x]
      #define rs rson[x]
      bool vis[maxn];
      int fa[maxn],dis[maxn];
      int lson[maxn],rson[maxn];
      
      struct node{
        int pos,val;
        bool operator < (const node &b) const{
          return val^b.val?val<b.val:pos<b.pos;  
        } 
      }v[maxn];
      
      int findf(int x){
        return fa[x]==x?x:fa[x]=findf(fa[x]);
      }
      
      int merge(int x,int y){
        if(!x||!y) return x+y;
        if(v[y]<v[x]) swap(x,y);
        rs=merge(rs,y);
        if(dis[ls]<dis[rs])swap(ls,rs);
        dis[x]=dis[rs]+1;
        return x;
      }
    }
    
    • 笛卡尔树
    signed main(){
      n=read();
      for(int i=1,k;i<=n;i++){
        a[i]=read();k=top;
        while(k&&a[zhan[k]]>a[i]) k--;
        if(k) rs[zhan[k]]=i;
        if(k<top) ls[i]=zhan[k+1];
        zhan[++k]=i;top=k;
      }
      for(int i=1;i<=n;i++)ans1^=(i*(ls[i]+1));
      for(int i=1;i<=n;i++)ans2^=(i*(rs[i]+1));
      printf("%lld %lld
    ",ans1,ans2);
      return 0;
    }
    
    • 主席树
    //静态区间第 k 小
    #define ls(x) t[x].ls
    #define rs(x) t[x].rs
    int n,m,all,cnt;
    int a[maxn],b[maxn],rt[maxn];
    struct node{int siz,ls,rs;}t[maxn];
    
    void insert(int last,int &now,int l,int r,int pos){
      if(!now) now=++cnt;
      t[now].siz=t[last].siz+1;
      if(l==r) return;int mid=l+r>>1;
      if(pos<=mid) t[now].rs=t[last].rs,insert(t[last].ls,t[now].ls,l,mid,pos);
      else t[now].ls=t[last].ls,insert(t[last].rs,t[now].rs,mid+1,r,pos);
    }
    
    int query(int last,int now,int l,int r,int val){
      if(l==r) return l;
      int lef=t[ls(now)].siz-t[ls(last)].siz;
      int mid=l+r>>1;
      if(val>lef) return query(t[last].rs,t[now].rs,mid+1,r,val-lef);
      else return query(t[last].ls,t[now].ls,l,mid,val);
    }
    
    int main(){    
      n=read();m=read();
      for(int i=1;i<=n;i++)b[i]=a[i]=read();
      sort(b+1,b+n+1);all=unique(b+1,b+n+1)-b-1;
      for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+all+1,a[i])-b;
    
      for(int i=1;i<=n;i++) insert(rt[i-1],rt[i],1,all,a[i]);
            
      for(int i=1,fr,to,val;i<=m;i++){
        fr=read();to=read();val=read();
        printf("%d
    ",b[query(rt[fr-1],rt[to],1,all,val)]);
      }
      return 0;
    } 
    
    • 各种平衡树(不在大纲中,但是会了总比不会好)
    namespace Treap{
      int insert(int x){
        val[++all]=x;
        dat[all]=rand();
        sum[all]=cnt[all]=1;
        return all;
      }
        
      void pushup(int x){
        sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+cnt[x];
      }
        
      void build(){
        root=insert(-INF);
        ch[root][1]=insert(INF);
        pushup(root);
      }
        
      void rotate(int &x,int son){
        int tmp=ch[x][son^1];
        ch[x][son^1]=ch[tmp][son];
        ch[tmp][son]=x;x=tmp;
        pushup(ch[x][son]);
        pushup(x); 
        }
        
      void push(int &x,int v){
        if(!x) {x=insert(v);return;}
        if(v==val[x]) cnt[x]++;
        else{
          int son=v<val[x]?0:1;push(ch[x][son],v);
          if(dat[x]<dat[ch[x][son]]) rotate(x,son^1);
        }
        pushup(x);
      }
        
      void Remove(int &x,int v){
        if(!x) return;
        if(v==val[x]){
          if(cnt[x]>1) {cnt[x]--,pushup(x);return;}
          if(ch[x][0]||ch[x][1]){
            if(!ch[x][1]||dat[ch[x][0]]>dat[ch[x][1]])
              rotate(x,1),Remove(ch[x][1],v);
            else rotate(x,0),Remove(ch[x][0],v);
            pushup(x); 
          }
          else x=0;return;
        }
        v<val[x]?Remove(ch[x][0],v):Remove(ch[x][1],v);
        pushup(x);
      }
        
      int getrank(int x,int v){
        if(!x) return -2;
        if(v==val[x]) return sum[ch[x][0]]+1;
        if(v<val[x]) return getrank(ch[x][0],v);
        return sum[ch[x][0]]+cnt[x]+getrank(ch[x][1],v);
      }
        
      int getval(int x,int rank){
        if(!x) return INF;
        if(rank<=sum[ch[x][0]]) return getval(ch[x][0],rank);
        if(rank<=sum[ch[x][0]]+cnt[x]) return val[x];
        return getval(ch[x][1],rank-sum[ch[x][0]]-cnt[x]);
      }
        
      int getpre(int v){
        int now=root,pre;
        while(now){
          if(val[now]<v) pre=val[now],now=ch[now][1];
          else now=ch[now][0];
        }
        return pre;
      }
        
      int getnxt(int v){
        int now=root,nxt;
        while(now){
          if(val[now]>v) nxt=val[now],now=ch[now][0];
          else now=ch[now][1];
        }
        return nxt;
      }
    }
    
    • ST表
    //静态区间最大值
    int n,m,a[maxn],Max[maxn][30],l,r;
    
    int Query(int lef,int rig){
      int k=log2(rig-lef+1);
      return max(Max[lef][k],Max[rig-(1<<k)+1][k]);
    }
    
    int main(){
      n=read();m=read();
      for(int i=1;i<=n;i++) scanf("%d",&Max[i][0]);
    
      for(int j=1;j<=30;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
          Max[i][j]=max(Max[i][j-1],Max[i+(1<<(j-1))][j-1]);
    
      for(int i=1;i<=m;i++){
        scanf("%d%d",&l,&r);
        printf("%d
    ",Query(l,r));
      }
      return 0;
    }
    

    数论类

    • BSGS
    //a^l % Mod = b 求最小非负整数 l(Mod 是质数)
    int BSGS(int a,int b,int Mod,int &ret){
      a%=Mod;b%=Mod;
      if(!a){if(!b){ret=1;return 1;}else return 0;}
      int m=ceil(sqrt(Mod));map<int,int> h;
      for(int i=0,tmp=b%Mod;i<=m;i++,tmp=tmp*a%Mod) h[tmp]=i;
      a=quickpow(a,m,Mod);
      for(int i=1,tmp=a%Mod;i<=m;i++,tmp=tmp*a%Mod)
        if(h.count(tmp)){ret=i*m-h[tmp];return 1;}
      return 0;
    }
    
    • CRT,EXCRT
    //CRT
    void exgcd(int a,int b,int &x,int &y){
      if(b==0){x=1;y=0;return;}
      exgcd(b,a%b,x,y);
      int z=x;x=y;y=z-y*(a/b);
    }
    
    signed main(){
      n=read();
      for(int i=1;i<=n;i++)
        a[i]=read(),b[i]=read(),M*=a[i];
      for(int i=1;i<=n;i++){
        times[i]=M/a[i];
        int x=0;int y=0;
        exgcd(times[i],a[i],x,y);
        ans+=b[i]*times[i]*(x<0?x+a[i]:x);
      }
      cout<<ans%M;
      return 0;
    }
    
    //EXCRT
    signed main(){
      n=read();
      int Ans,M,x,y;
      for(rr int i=1;i<=n;i++)
        m[i]=read(),a[i]=read();
        M=m[1],Ans=a[1];
        for(int i=2,A,B,C;i<=n;i++){
          A=M,B=m[i],C=(a[i]-Ans%B+B)%B;
          int now=exgcd(A,B,x,y),f=B/now;
          x=quicktimes(x,C/now,f);
          Ans+=x*M;M*=f;Ans=(Ans%M+M)%M;
        }
        printf("%lld
    ",Ans);
      }
      return 0;
    }
    
    • 拉格朗日插值(朴素)
    signed main(){
      n=read();k=read();
      for(int i=1;i<=n;i++)
        x[i]=read(),y[i]=read();
      for(int i=1,fir,sec;i<=n;i++){
        fir=y[i]%Mod,sec=1;
        for(int j=1;j<=n;j++){
          if(i==j) continue;
          fir=fir*(k-x[j])%Mod;
          sec=sec*(x[i]-x[j])%Mod;
        }
        Ans=(Ans+(fir*quickpow(sec,Mod-2)%Mod)+Mod)%Mod;
      }
      printf("%lld
    ",Ans);
      return 0;
    }
    
    • 拉格朗日插值(自变量取值连续时)
    signed main(){
      n=read();k=read();pre[0]=fac[0]=suf[k+3]=1;
      for(int i=k+2;i>=1;i--)suf[i]=suf[i+1]*(n-i)%Mod;
      for(int i=1;i<=k+2;i++)
        fac[i]=fac[i-1]*i%Mod,pre[i]=pre[i-1]*(n-i)%Mod;
      for(int i=1,fir,sec;i<=k+2;i++){
        tmp=(tmp+quickpow(i,k))%Mod;
        fir=pre[i-1]*suf[i+1]%Mod;
        sec=fac[i-1]*((k-i)&1?-1:1)*fac[k+2-i]%Mod;
        ans=((ans+tmp*fir%Mod*quickpow(sec,Mod-2)%Mod)%Mod+Mod)%Mod;
      }
      printf("%lld
    ",ans);
      return 0;
    }
    
    • 高斯消元
    int main(){
      n=read();
      for(int i=1;i<=n;i++)
        for(int j=1;j<=n+1;j++)
          scanf("%lf",&Gu[i][j]);
      for(int i=1,Max;i<=n;i++){
        Max=i;
        for(int j=i+1;j<=n;j++)
          if(fabs(Gu[j][i])>fabs(Gu[Max][i]))Max=j;
        for(int j=1;j<=n+1;j++) swap(Gu[i][j],Gu[Max][j]);
        if(!Gu[i][i]) {printf("No Solution
    ");return 0;}
        for(int j=1;j<=n;j++){
          if(j==i) continue;double tmp=Gu[j][i]/Gu[i][i];
          for(int k=i+1;k<=n+1;k++) Gu[j][k]-=Gu[i][k]*tmp;
        }
      }
      for(int i=1;i<=n;i++) printf("%.2lf
    ",Gu[i][n+1]/Gu[i][i]);
      return 0;
    }
    
    • 各种定理

    字符串类

    • Trie
    struct Trie{
      int Nxt[maxn][15],tot;
      void Insert(char *s){
        int u=0;
        for(int i=1;s[i];i++){
          if(!Nxt[u][s[i]]) Nxt[u][s[i]]=++tot;
          u=Nxt[u][s[i]];
        }
      }
      int Find(char *s){
        int p=0,len=strlen(s+1);
        if(Judge[s+1]) return Get[s+1];
        memset(vis,false,sizeof vis);vis[0]=true;
        for(int i=0;i<=len;i++){
          if(!vis[i]) continue;cnt=i;
          for(int j=i+1;j<=len;j++){
            int c=s[j]-'a';
            p=Nxt[p][c];if(!p) break;
            if(flag[p]) vis[j]=true;
          }
        }
        Judge[s+1]=true;Get[s+1]=cnt;
        return cnt;//能匹配到的最长前缀长度
      }
    }trie;
    
    • AC自动机
    namespace Automaton{
      int Nxt[maxn][30],Fail[maxn];
      int tot,e[maxn];queue<int> q;
      void Insert(char *s){
        int u=0;
        for(int i=1;s[i];i++){
          if(!Nxt[u][s[i]-'a']) Nxt[u][s[i]-'a']=++tot;
          u=Nxt[u][s[i]-'a'];
        }
        e[u]++;
      }
    	
      void Build(){
        for(int i=0;i<26;i++)
          if(Nxt[0][i]) q.push(Nxt[0][i]);
        while(!q.empty()){
          int u=q.front();q.pop();
          for(int i=0;i<26;i++){
            if(Nxt[u][i]) Fail[Nxt[u][i]]=Nxt[Fail[u]][i],q.push(Nxt[u][i]);
            else Nxt[u][i]=Nxt[Fail[u]][i];
          }
        }
      }
    		
      int Query(char *s){
        int u=0,ans=0;
        for(int i=1;s[i];i++){
          u=Nxt[u][s[i]-'a'];
          for(int j=u;j&&e[j]!=-1;j=Fail[j]){//
            ans+=e[j],e[j]=-1;
          }
        }
        return ans;
      }
    }
    
    • KMP,EXKMP
    //KMP
    Kmp[0]=Kmp[1]=0;
      int n=strlen(A+1),m=strlen(B+1);
      for(int i=1;i<m;i++){
        while(j&&B[j+1]!=B[i+1]) j=Kmp[j];
        if(B[i+1]==B[j+1]) j++,Kmp[i+1]=j;
      }
      j=0;
      for(i=0;i<n;i++){
        while(j&&B[j+1]!=A[i+1]) j=Kmp[j];
        if(B[j+1]==A[i+1]) ++j;
        if(j==m) printf("%d
    ",i+2-m),j=Kmp[j];
      }
    
    //EXKMP
    void Getnxt(){
      nxt[0]=m;int now=0,p0=1;
      while(t[now]==t[1+now]&&now+1<m) now++;
      nxt[1]=now;
      for(int i=1;i<m;i++){
        if(i+nxt[i-p0]<nxt[p0]+p0) nxt[i]=nxt[i-p0];
        else{
          int now=p0+nxt[p0]-i;now=max(now,0*1ll);
          while(now+i<m&&t[now]==t[now+i]) now++;
          nxt[i]=now;p0=i;
        }
      }     
    }
    
    void Exkmp(){
      Getnxt();int now=0,p0=0;
      while(s[now]==t[now]&&now<m&&now<n) now++;
      extend[0]=now;
      for(int i=1;i<n;i++){
        if(i+nxt[i-p0]<extend[p0]+p0) extend[i]=nxt[i-p0]; 
        else{
          int now=extend[p0]+p0-i;now=max(now,0*1ll);
          while(t[now]==s[now+i]&&now<m&&now+i<n) now++;
          extend[i]=now;p0=i;
        }
      }
    } 
    
    • 后缀数组(朴素)
    bool cmp(int x,int y){
      return rk[x]^rk[y]?rk[x]<rk[y]:rk[x+w]<rk[y+w];
    }
    
    int main(){
      scanf("%s",s+1);n=strlen(s+1);
      for(int i=1;i<=n;i++)sa[i]=i,rk[i]=s[i];
      for(w=1;w<n;w<<=1){
        sort(sa+1,sa+n+1,cmp);
        for(int i=1;i<=n;i++)oldrk[i]=rk[i];
        for(int i=1,p=0;i<=n;i++){
          if(oldrk[sa[i]]==oldrk[sa[i-1]]&&
            oldrk[sa[i]+w]==oldrk[sa[i-1]+w])
            rk[sa[i]]=p;
          else rk[sa[i]]=++p;
        }
      }
      for(int i=1;i<=n;i++) printf("%d ",sa[i]);
      return 0;
    }
    
    • manacher
    void build(){
      scanf("%s",c+1);n=strlen(c+1);
      s[++cnt]='~',s[++cnt]='#';
      for(int i=1;i<=n;i++)
        s[++cnt]=c[i],s[++cnt]='#';
      s[++cnt]='!';
    }
    
    void work(){
      for(int i=2;i<=cnt-1;i++){
        if(i<=mr) p[i]=min(p[mid*2-i],mr-i+1);
        else p[i]=1;while(s[i-p[i]]==s[i+p[i]]) p[i]++;
        if(i+p[i]>mr)mr=i+p[i]-1,mid=i;Ans=max(Ans,p[i]);
      }
    }
    
    int main(){
      build();work();
      printf("%d
    ",Ans-1);
      return 0;
    }
    

    动态规划类

    • 状压、区间、树形、数位、背包等,基本都看。

    其他的

    不知道怎么分类的知识点。

    • 各种排序(基数排序,归并排序,锦标赛排序等)
    //基数排序
    inline void Radixsort(){
      for(rr int i=1;i<256;i++) cnt[i]=0;
      for(rr int i=1;i<=n;i++) ++cnt[a[i]&255];
      for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
      for(rr int i=n;i>=1;i--) b[cnt[a[i]&255]--]=a[i];
      
      for(rr int i=1;i<256;i++) cnt[i]=0;
      for(rr int i=1;i<=n;i++) ++cnt[b[i]>>8&255];
      for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
      for(rr int i=n;i>=1;i--) a[cnt[b[i]>>8&255]--]=b[i];
      
      for(rr int i=1;i<256;i++) cnt[i]=0;
      for(rr int i=1;i<=n;i++) ++cnt[a[i]>>16&255];
      for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
      for(rr int i=n;i>=1;i--) b[cnt[a[i]>>16&255]--]=a[i];
      
      for(rr int i=1;i<256;i++) cnt[i]=0;
      for(rr int i=1;i<=n;i++) ++cnt[b[i]>>24&255];
      for(rr int i=1;i<256;i++) cnt[i]+=cnt[i-1];
      for(rr int i=n;i>=1;i--) a[cnt[b[i]>>24&255]--]=b[i];
    }
    
    //归并排序
    void Merge(int l,int r){
      if(r-l<=1) return;
      int mid=l+(r-l>>1);
      Merge(l,mid);Merge(mid,r);
      int p=l,q=mid,s=l;
      while(s<r){
        if(p>=mid||(q<r&&a[p]>a[q])){
          t[s++]=a[q++];//cnt+=mid-p;
        }
        else t[s++]=a[p++];
      }
      for(int i=l;i<r;i++) a[i]=t[i];
    }
    
    //锦标赛排序
    int winner(int pos1,int pos2){
      int fr=pos1>=n?pos1:tmp[pos1];
      int to=pos2>=n?pos2:tmp[pos2];
      return tmp[fr]<=tmp[to]?fr:to;
    }
    
    void build(int &v){
      for(int i=0;i<n;i++)tmp[n+i]=a[i];
      for(int i=2*n-1,k,j;i>1;i-=2)
        k=i/2,j=i-1,tmp[k]=winner(i,j);
      v=tmp[tmp[1]];tmp[tmp[1]]=INF;
    }
    
    void rebuild(int &v){
      int i=tmp[1];
      while(i>1){
        int j,k=i/2;
        if(!(i%2)&&i<2*n-1) j=i+1;
        else j=i-1;tmp[k]=winner(i,j); 
        i=k;
      }
      v=tmp[tmp[1]];
      tmp[tmp[1]]=INF;
    }
    
    void TournamentSort(){
      int v;build(v);
      for(int i=0;i<n;i++)
        a[i]=v,rebuild(v);
    }
    
    • 线性基
    void insert(int k){
      for(int i=len;i>=0;i--){
        if(!(k&(1ll<<i))) continue;
        if(!p[i]){p[i]=k;return;}
        k^=p[i];
      }
    }
    
    signed main(){
      n=read();
      for(int i=1;i<=n;i++) insert(read());
      for(int i=len;i>=0;i--) ans=max(ans,(ans^p[i]));
      printf("%lld
    ",ans);
      return 0;
    }
    
    • 各种 STL
  • 相关阅读:
    Vi 和 Vim
    The C Programming Language-Chapter 5 Pointers and Arrays
    C# 4.0开始,泛型接口和泛型委托都支持协变和逆变
    数据库中的锁 and java StampedLock ReadWriteLock
    NetCore and ElasticSearch 7.5
    网关项目 ReverseProxy
    异常捕获&打印异常信息
    刷新:重新发现.NET与未来
    2019 中国.NET 开发者峰会正式启动
    .NET开发者必须学习.NET Core
  • 原文地址:https://www.cnblogs.com/KnightL/p/14898881.html
Copyright © 2011-2022 走看看