1. 程式人生 > 其它 >CSP/NOIP 之前還需要學/複習的東西

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]);
  }
}

資料結構類

  • 哈夫曼樹
  • 笛卡爾樹
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;
}
  • Lucas,EXLucas
下午再填坑。
  • 高斯消元
  • 各種定理

字串類

  • Trie
  • AC自動機
  • KMP,EXKMP
  • 字尾陣列
  • Manacher

動態規劃類

  • 狀壓、區間、樹形、數位、揹包等,基本都看。

其他的

不知道怎麼分類的知識點。

  • 各種排序(基數排序,歸併排序,錦標賽排序等)
  • 各種 STL