ACM常用模板(持续更新)

头文件

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e6) + 10;
const int mod = 998244353;
const int inf = 1e9;
inline int rd() {
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
signed main() {
  
  return 0;
}

DP

基于连通性的状态压缩

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
#define int long long
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e5) + 10;
const int mod = 1e9+7;
const int inf = 1e9 + 10;
const int hs = 299987;
inline int rd() {
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}

int a[14][14],inc[14]; char s[14][14]; int n,m,ex,ey; int ans = 0;

int cnt[2],val[2][(1<<25) + 10],que[2][(1<<25) + 10],nex[(1<<25) + 10],fir[hs + 10];
int now,last;

void ins(int sta,int num) {
  int u = sta % hs + 1;
  for(int k=fir[u];k!=-1;k=nex[k]) {
    if(que[now][k] == sta) {
      val[now][k] = (val[now][k] + num);
      return ;
    }
  }
  nex[++cnt[now]] = fir[u];
  fir[u] = cnt[now];
  que[now][cnt[now]] = sta;
  val[now][cnt[now]] = num;
}

void dp() {
  cnt[now] = 1; val[now][1] = 1; que[now][1] = 0; 
  for(int i=1;i<=n;++i) {
    for(int j=1;j<=cnt[now];j++) que[now][j] <<= 2;
    for(int j=1;j<=m;j++) {
      memset(fir,-1,sizeof(fir));
      last = now; now ^= 1;
      cnt[now] = 0;
      for(int k=1;k<=cnt[last];k++) {
        int sta = que[last][k]; int num = val[last][k];
        int b1 = (sta>>((j-1)*2))%4; int b2 = (sta>>(j*2))%4;
        if(!a[i][j]) {
          if(!b1 && !b2) ins(sta,num);
        }else if(!b1 && !b2) {
          if(a[i+1][j] && a[i][j+1]) ins(sta+inc[j-1]+inc[j]*2,num);
        }else if(!b1 && b2) {
          if(a[i][j+1]) ins(sta,num);
          if(a[i+1][j]) ins(sta-b2*inc[j]+b2*inc[j-1],num);
        }else if(b1 && !b2) {
          if(a[i+1][j]) ins(sta,num);
          if(a[i][j+1]) ins(sta-b1*inc[j-1]+b1*inc[j],num);
        }else if(b1 == 1 && b2 == 1) {
          for(int c=1,p=j+1;p<=m;p++) {
            if((sta>>(p*2)) % 4 == 1) c++;
            if((sta>>(p*2)) % 4 == 2) c--;
            if(!c) {
              ins(sta-inc[j-1]-inc[j]-inc[p],num);
              break;
            }
          }
        }else if(b1 == 2 && b2 == 2) {
          for(int c=1,p=j-2;p>=0;p--) {
            if((sta>>(p*2)) % 4 == 1) c--;
            if((sta>>(p*2)) % 4 == 2) c++;
            if(!c) {
              ins(sta-inc[j-1]*2-inc[j]*2+inc[p],num);
              break;
            }
          }
        }else if(b1 == 2 && b2 == 1) {
          ins(sta-inc[j-1]*b1-inc[j]*b2,num);
        }else if(i==ex && j==ey) ans = (ans + num);
      }
    }
  }
}

signed main() {
  n = rd(); m = rd();
  for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) {
    scanf("\n%c",&s[i][j]);
    if(s[i][j] == '.') {a[i][j] = 1; ex = i; ey = j;}
  }
  inc[0] = 1; for(int i=1;i<=13;i++) inc[i] = inc[i-1] << 2;
  dp();
  printf("%lld\n",ans);
}

数据结构

Link_Cut_Tree

可撤销并查集版本:

struct Link_Cut_Tree {
  int ch[N][2],fa[N]; bool rev[N];
  bool Is_root(int x){return (ch[fa[x]][0] != x) && (ch[fa[x]][1] != x);}
  void push_down(int x) {
    if(rev[x]) {
      if(ch[x][0]){swap(ch[ch[x][0]][0] , ch[ch[x][0]][1]); rev[ch[x][0]] ^= 1;}
      if(ch[x][1]){swap(ch[ch[x][1]][0] , ch[ch[x][1]][1]); rev[ch[x][1]] ^= 1;}
      rev[x] = 0;
    }
  }
  void push_all(int x) {
    if(!Is_root(x)) push_all(fa[x]);
    push_down(x);
  }
  void rotate(int x) {
    int y = fa[x]; int z = fa[y];
    int a = ch[y][1] == x; int b = ch[z][1] == y;
    int g = ch[x][a^1];
    if(!Is_root(y)) ch[z][b] = x; fa[x] = z;
    ch[y][a] = g; if(g) fa[g] = y;
    ch[x][a^1] = y; fa[y] = x;
  }
  void splay(int x) {
    push_all(x);
    while(!Is_root(x)) {
      int y = fa[x]; int a = ch[y][1] == x;
      if(!Is_root(y)) {
        int z = fa[y]; int b = ch[z][1] == y;
        if(a==b) rotate(y); else rotate(x);
      }rotate(x);
    }
  }
  void access(int x) {
    int last = 0;
    while(x){splay(x); ch[x][1] = last; last = x; x = fa[x];}
  }
  void make_root(int x) {
    access(x);
    splay(x);
    swap(ch[x][0],ch[x][1]); rev[x] ^=1; 
  }
  void split(int x,int y) {
    make_root(x);
    access(y);
    splay(y);
  }
  void link(int x,int y) {
    make_root(x); fa[x] = y;
  }
  void cut(int x,int y) {
    split(x,y);
    fa[ch[y][0]] = 0; ch[y][0] = 0;
  }
  bool Is_connect(int x,int y) {
    split(x,y);
    while(ch[y][0]) push_down(y),y = ch[y][0];
    return (y==x);
  }
}t;

字符串

最小表示法

  int k = 0,i = 0,j = 1;
  while(k<n && i<n && j<n) {
    if(str[(i+k)%n] == str[(j+k)%n]) k++;
    else {
      if(str[(i+k)%n] > str[(j+k)%n]) i++;
      else j++;
      k = 0;
      if(i==j) i++;
    }
  }
  i = min(i,j);

KMP

两串匹配,A是文本串,B是模式串,寻找A在B那出现的位置

int nex[N],p[N];
p[1] = 0; int j=0; for(int i=2;i<=m;i++) {
  while(j && b[i] != b[j+1]) j=p[j];
  if(b[i] == b[j+1]) j++;
  p[i] = j;
}
int ans = 0; // 注意:这里如果匹配数字时末尾有0的情况,应该在模式串b的末尾加一个字符
j = 0; for(int i=1;i<=n;i++) {
  while(j && a[i] != b[j+1]) j=p[j];
  if(a[i] == b[j+1]) j++;
  nex[i] = j; if(nex[i] == m){printf("%lld\n",i-m+1);}
}

数学

多项式

快速傅里叶变换

struct Complex {
  long double r,i;
  Complex(){}
  Complex(long double _r,long double _i){r=_r; i=_i;}
  friend Complex operator + (const Complex &x,const Complex &y) {return Complex(x.r+y.r,x.i+y.i);}
  friend Complex operator - (const Complex &x,const Complex &y) {return Complex(x.r-y.r,x.i-y.i);}
  friend Complex operator * (const Complex &x,const Complex &y) {return Complex(x.r*y.r-x.i*y.i,x.i*y.r+x.r*y.i);}
}A[N<<2],B[N<<2],C[N<<2]; int R[N<<2];

void DFT(Complex *a,int n,int op) {
  for(int i=0;i<n;i++) if(R[i] > i) swap(a[i],a[R[i]]);
  for(int i=1;i<n;i<<=1) {
    Complex wn = Complex(cos(i),sin(i));
    for(int j=0;j<n;j+=(i<<1)) {
      Complex w = Complex(1.0,0.0);
      for(int k=0;k<i;k++,w=w*wn) {
        Complex x = a[j+k]; Complex y = a[j+k+i]*w;
        a[j+k] = x+y;
        a[j+k+i] = x-y;
      }
    }
  }
  if(op == -1) reverse(a+1,a+n);
}

void FFT(int n,int m) {
  m=m+n; int l=0; for(n=1;n<=m;n<<=1) l++;
  R[0] = 0; for(int i=1;i<n;i++) R[i] = (R[i>>1] >> 1) | ((i&1) << (l-1));
  DFT(A,n,1); DFT(B,n,1);
  for(int i=0;i<n;i++) C[i] = A[i] * B[i];
  DFT(C,n,-1);
  for(int i=0;i<n;i++) C[i].r = (int)(round(C[i].r/n));
}

快速沃尔什变换

学习资料

int qpow(int x,int k,int mo) {
  int s = 1;
  while(k) {
    if(k&1) s=s*x%mo;
    x=x*x%mo; k>>=1;
  }return s;
}
void FWT(int *a,int n,int op) {
  int inv2 = qpow(2ll,mod-2,mod);
  for(int k=1;k<n;k<<=1)
    for(int i=0;i<n;i+=(k<<1))
      for(int j=0;j<k;j++) {
        int x = a[i+j]; int y=a[i+j+k];
        if(op == 1) {
          // a[i+j+k] = (y+x) % mod; // or
          // a[i+j] = (x+y) % mod; // and
          // a[i+j] = (x+y); a[i+j+k] = (x-y+mod) % mod; // xor
        }
        else if(op == -1) {
          // a[i+j+k] = (y-x+mod) % mod; // or
          // a[i+j] = (x-y+mod) % mod; // and
          // a[i+j] = (x+y)%mod*inv2%mod; a[i+j+k] = (x-y+mod)%mod*inv2%mod; // xor
        }
      }
}

倍增子集卷积(多子集卷积)
设多项式 A = i = 0 2 n 1 a i x i , B = i = 0 2 n 1 b i x i A=\sum\limits_{i=0}^{2^n-1}a_ix^i,B=\sum\limits_{i=0}^{2^n-1}b_ix^i
C = A B = i = 0 2 n 1 x i d i a d b i d C=A*B=\sum\limits_{i=0}^{2^n-1}x^i\sum\limits_{d \subseteq i}a_d b_{i-d} 可以用 O ( n 2 2 n ) O(n^22^n) 来完成
具体就是按照每个状态的最高位进行分组,然后卷n次,这样的复杂度计算是 O ( i = 1 n i 2 2 i ) = O ( n 2 2 n ) O(\sum\limits_{i=1}^{n}i^22^i) = O(n^22^n)

#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define dep(i,a,b) for(int i=(a);i>=(b);--i)
#define MP make_pair
#define fi first
#define se second
#define PB push_back
#define CL clear
#define pii pair<int,int>
// #define int long long
using namespace std;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
const int N = (int)(1e6) + 10;
const int mod = 998244353;
const int inf = 1e9;
inline int rd() {
  int p=0; int f=1; char ch=getchar();
  while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
  while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
  return p*f;
}
struct node{int p,b;}w[N];
bool cmp(const node &x,const node &y){return x.b<y.b;}
int a[22][(1<<21)+1],b[22][(1<<21)+1],c[(1<<21)+1];

void FWT(int *a,int n,int op) {
  for(int k=1;k<n;k<<=1)
    for(int i=0;i<n;i+=(k<<1))
      for(int j=0;j<k;j++) {
        int x = a[i+j]; int y=a[i+j+k];
        if(op == 1) {
          // a[i+j+k] = (y+x) % mod; // or
          // a[i+j] = (x+y) % mod; // and
          // a[i+j] = (x+y); a[i+j+k] = (x-y+mod) % mod; // xor
        }
        else if(op == -1) {
          // a[i+j+k] = (y-x+mod) % mod; // or
          // a[i+j] = (x-y+mod) % mod; // and
          // a[i+j] = (x+y)%mod*inv2%mod; a[i+j+k] = (x-y+mod)%mod*inv2%mod; // xor
        }
      }
}

int ans[(1<<21)+1];
signed main() {
  int n = rd();
  rep(i,1,n) w[i].p = rd(),w[i].b = rd();
  sort(w+1,w+n+1,cmp); int j = 1;
  while(w[j].b < 2 && j<=n) (a[__builtin_popcount(w[j].b)][w[j].b] += w[j].p) %= mod,j++; a[0][0] = 1; ans[1] = a[1][1]; 
  rep(i,2,21) {
    b[0][0] = 1; while(w[j].b < (1ll<<i) && j<=n) {
      (b[__builtin_popcount(w[j].b)][w[j].b] += w[j].p) %= mod;
      j++;
    }
    for(int k=0;k<=i;k++) FWT(a[k],(1ll<<i),1),FWT(b[k],(1ll<<i),1);
    for(int k1=i;k1>=0;k1--) {
      for(int k2=0;k2<=k1;k2++) for(int p=0;p<(1ll<<i);p++) {
        c[p] = (1ll * c[p] + 1ll * a[k2][p] * b[k1-k2][p]) % mod;
      }
      FWT(c,(1<<i),-1);
      memcpy(a[k1],c,sizeof(c));

      for(int p=0;p<(1ll<<i);p++) c[p] = 0;
    }
    for(int k=(1ll<<(i-1));k<(1ll<<i);k++) ans[k] = (ans[k] + a[__builtin_popcount(k)][k]) % mod;
    for(int k=0;k<=i;k++) for(int p=0;p<(1ll<<i);p++) b[k][p] = 0;
  }
  int q = rd(); while(q--){int x=rd(); printf("%d\n",ans[x]);}

  return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39708759/article/details/107965003