Loading

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\n%lld\n",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\n",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\n",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\n",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\n",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\n",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\n",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\n");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\n",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\n",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\n",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\n",ans);
  return 0;
}
  • 各种 STL
posted @ 2021-06-18 11:40  KnightL  阅读(59)  评论(1编辑  收藏  举报