acm常用模板

来源:互联网 发布:淘宝账户自助开通页面 编辑:程序博客网 时间:2024/06/07 09:28

      • 数位dp
        • moban
        • HDU 5787 K-wolf Number数位dp
        • 二维bit优化dp
    • 数据结构
      • 后缀数组
      • AC自动机
        • 在线AC自动机
      • 回文树
      • 主席树
        • 标记永久化
        • prefix字典树 hdu5790
      • 二叉搜索树
        • nlogn建树kmp
      • 可持久化Trie
        • HDU 5801 Up SkyMrZhu
      • 树上莫队
        • SPOJ Count on a tree II树上莫队
        • HDU 5799 This world need more Zhu树上莫队
      • 线段树
        • AOJ 2450 Do use segment tree 树链剖分 线段树区间合并
        • HDU 5737 Differencia归并树
        • UVA 11402 Ahoy Pirates线段树标记合并
      • POJ 3168 Barn Expansion扫描线
    • 数学
      • FFT
        • HDU 5730 Shell Necklacedpcdq分治FFT
      • NTT
        • HDU 5829 Rikka with Subset NTT
      • FWT
        • IForg 1028 Bob and Alice are playing numbers
        • SRM 518 NIM
        • Codeforces 449D Jzzhu and Numbers
    • 其他
      • 树Hash
        • HDU 5732 Subway树哈希
        • VK Cup 2016 - Round 1 D Bear and Polynomials哈希
        • Codeforces Round 354 Div 2 E The Last Fight Between Human and AI
      • 生成树计数

数位dp

moban

//    pos    = 当前处理的位置(一般从高位到低位)//    pre    = 上一个位的数字(更高的那一位)//    status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回,//            给计数器+1。//    limit  = 是否受限,也即当前处理这位能否随便取值。如567,当前处理6这位,//            如果前面取的是4,则当前这位可以取0-9。如果前面取的5,那么当前//            这位就不能随便取,不然会超出这个数的范围,所以如果前面取5的//            话此时的limit=1,也就是说当前只可以取0-6。////    用DP数组保存这三个状态是因为往后转移的时候会遇到很多重复的情况。int    dfs(int pos,int pre,int status,int limit){    //已结搜到尽头,返回"是否找到了答案"这个状态。    if(pos < 1)        return    status;    //DP里保存的是完整的,也即不受限的答案,所以如果满足的话,可以直接返回。    if(!limit && DP[pos][pre][status] != -1)        return    DP[pos][pre][status];    int    end = limit ? DIG[pos] : 9;    int    ret = 0;    //往下搜的状态表示的很巧妙,status用||是因为如果前面找到了答案那么后面    //还有没有答案都无所谓了。而limti用&&是因为只有前面受限、当前受限才能    //推出下一步也受限,比如567,如果是46X的情况,虽然6已经到尽头,但是后面的    //个位仍然可以随便取,因为百位没受限,所以如果个位要受限,那么前面必须是56。    //    //这里用"不要49"一题来做例子。    for(int i = 0;i <= end;i ++)        ret += dfs(pos - 1,i,status || (pre == 4 && i == 9),limit && (i == end));    //DP里保存完整的、取到尽头的数据    if(!limit)        DP[pos][pre][status] = ret;    return    ret;}

HDU 5787 K-wolf Number(数位dp)

/*- 求1≤L≤R≤1018范围内,每2≤K≤5个数字都不同的数字有多少- f[i][pre][5]:=从高到低,填到第i位,且之前的数字是pre,pre已经有1∼4位数合法数字数- 由于不能有前导0,所以开个first判一判,其他套个板子就好了*/const int N = 1e4 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;LL l, r, f[20][N][5];int k;const int ten[] = {1, 10, 100, 1000, 10000, 100000};int get(int x, int i) {    return x / ten[i] % 10;}int add(int x, int y) {    return (x * 10 + y) % ten[k - 1];}int digit[20];LL dfs(int i, int pre, int num, bool first, bool e) {    if(!i) return 1;    if(!e && ~f[i][pre][num]) return f[i][pre][num];    LL ret = 0;    int to = e ? digit[i] : 9;    for(int d = 0; d <= to; ++d) {        bool ok = true;        for(int j = 0; j < min(k - 1, num) && ok; ++j)            if(get(pre, j) == d) ok = false;        if(!ok) continue;        ret += dfs(i - 1, first && !d ? 0 : add(pre, d),                   first && !d ? 0 : min(k - 1, num + 1),                   first && !d, e && d == to);    }    return e ? ret : f[i][pre][num] = ret;}LL calc(LL x) {    int cnt = 0;    for(; x; x /= 10) digit[++cnt] = x % 10;    return dfs(cnt, 0, 0, 1, 1);}bool judge(int x, int k) {    int cnt = 0;    for(; x; x /= 10) digit[++cnt] = x % 10;    for(int i = 1; i <= cnt; ++i) {        bool ok = true;        for(int j = 1; j < k; ++j) {            if(i - j >= 1 && digit[i] == digit[i - j]) {                ok = false;                break;            }        }        if(!ok) return false;    }    return true;}int main() {    ios_base::sync_with_stdio(0);    while(scanf("%I64d%I64d%d", &l, &r, &k) == 3) {        memset(f, -1, sizeof f);        LL ans = calc(r) - calc(l - 1);        printf("%I64d\n", ans);    }    return 0;}

二维bit优化dp

/*cf355 (Div. 2) D. Vanya and Treasure(dp、二维BIT优化)题意:N,M≤300,P≤N×M,给定一个N×M图,每个格子Aij是1∼P的数字从(1, 1)出发,两个格子的距离定义为曼哈顿距离,按顺序取1∼P的数字问最短路是多少优化一:令cnt[i]:=i这个数字的个数,当cnt[i−1]×cnt[i]≤n×m的时候直接更新,否则bfs一波这个时间复杂度是O(nmnm−−−√),如果有人懂详细证明请教我。。优化二:我们展开这个dp转移方程:f[x2][y2]=min{ f[x1][y1]+abs(x1−x2)+abs(y1−y2) }*/const int N = 300 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, m, p;int s[N][N], f[N][N];typedef pair<int, int> P;vector<P> G[N * N];struct BIT {    int n, b[N][N];    int timStp, vis[N][N];    void init(int _n) {        n = _n;        timStp = 1;        memset(vis, 0, sizeof vis);    }    void newOne() {        ++timStp;    }    void update(int x, int y, int v) {        for(int i = x; i <= n; i += i & -i) {            for(int j = y; j <= n; j += j & -j) {                if(vis[i][j] != timStp) vis[i][j] = timStp, b[i][j] = INF;                b[i][j] = min(b[i][j], v);            }        }    }    int query(int x, int y) {        int ret = INF;        for(int i = x; i; i -= i & -i)            for(int j = y; j; j -= j & -j)                if(vis[i][j] == timStp) ret = min(ret, b[i][j]);        return ret;    }} bit[4];int main() {    ios_base::sync_with_stdio(0);    scanf("%d%d%d", &n, &m, &p);    for(int i = 1; i <= n; ++i) {        for(int j = 1; j <= m; ++j) {            scanf("%d", s[i] + j);            G[s[i][j]].push_back({i, j});        }    }    memset(f, 0x3f, sizeof f);    int nm = max(n, m);    for(int i = 0; i < 4; ++i) bit[i].init(nm);    //UL - f[x2][y2] = min { f[x1][y1] - x1 - y1 + x2 + y2 }    //UR - f[x2][y2] = min { f[x1][y1] + x1 - y1 - x2 + y2 }    //BR - f[x2][y2] = min { f[x1][y1] + x1 + y1 - x2 - y2 }    //BL - f[x2][y2] = min { f[x1][y1] - x1 + y1 + x2 - y2 }    for(int i = 0; i < G[1].size(); ++i) {        int x = G[1][i].first, y = G[1][i].second;        f[x][y] = x + y - 2;        bit[0].update(x, y, f[x][y] - x - y);        bit[1].update(nm - x + 1, y, f[x][y] + x - y);        bit[2].update(nm - x + 1, nm - y + 1, f[x][y] + x + y);        bit[3].update(x, nm - y + 1, f[x][y] - x + y);    }    for(int i = 2; i <= p; ++i) {        for(int j = 0; j < G[i].size(); ++j) {            int x = G[i][j].first, y = G[i][j].second, val = INF;            val = min(val, bit[0].query(x, y) + x + y);            val = min(val, bit[1].query(nm - x + 1, y) - x + y);            val = min(val, bit[2].query(nm - x + 1, nm - y + 1) - x - y);            val = min(val, bit[3].query(x, nm - y + 1) + x - y);            f[x][y] = val;        }        for(int j = 0; j < 4; ++j) bit[j].newOne();        for(int j = 0; j < G[i].size(); ++j) {            int x = G[i][j].first, y = G[i][j].second;            bit[0].update(x, y, f[x][y] - x - y);            bit[1].update(nm - x + 1, y, f[x][y] + x - y);            bit[2].update(nm - x + 1, nm - y + 1, f[x][y] + x + y);            bit[3].update(x, nm - y + 1, f[x][y] - x + y);        }    }    int x = G[p][0].first, y = G[p][0].second;    printf("%d\n", f[x][y]);    return 0;}
/*ZOJ 3256N*M(2<=N<=7,1<=M<=10^9)的方格,问从左上角的格子到左下角的格子,而且仅经过所有格子一次的路径数插头DP+矩阵加速对于一个图的邻接矩阵的N次方,其中(i,j)位置上的元素表示点i经过N步到达点j的方案数*/#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>using namespace std;const int STATE=1010;const int HASH=419;//这个小一点,效率高const int MOD=7777777;int N,M;int D;int code[10];int ch[10];int g[200][200];//状态转移图struct Matrix{    int n,m;    int mat[200][200];};Matrix mul(Matrix a,Matrix b)//矩阵相乘,要保证a的列数和b的行数相等{    Matrix ret;    ret.n=a.n;    ret.m=b.m;    long long sum;    for(int i=0;i<a.n;i++)       for(int j=0;j<b.m;j++)       {           sum=0;           for(int k=0;k<a.m;k++)           {               sum+=(long long)a.mat[i][k]*b.mat[k][j];               //sum%=MOD;//加了这句话就会TLE,坑啊。。。           }           ret.mat[i][j]=sum%MOD;       }    return ret;}Matrix pow_M(Matrix a,int n)//方阵的n次方{    Matrix ret=a;    memset(ret.mat,0,sizeof(ret.mat));    for(int i=0;i<a.n;i++)ret.mat[i][i]=1;//单位阵    Matrix temp=a;    while(n)    {        if(n&1)ret=mul(ret,temp);        temp=mul(temp,temp);        n>>=1;    }    return ret;}struct HASHMAP{    int head[HASH],next[STATE],size;    int state[STATE];    void init()    {        size=0;        memset(head,-1,sizeof(head));    }    int push(int st)    {        int i,h=st%HASH;        for(i=head[h];i!=-1;i=next[i])           if(state[i]==st)              return i;        state[size]=st;        next[size]=head[h];        head[h]=size++;        return size-1;    }}hm;void decode(int *code,int n,int st){    for(int i=n-1;i>=0;i--)    {        code[i]=st&3;        st>>=2;    }}int encode(int *code,int n){    int cnt=1;    memset(ch,-1,sizeof(ch));    ch[0]=0;    int st=0;    for(int i=0;i<n;i++)    {        if(ch[code[i]]==-1)ch[code[i]]=cnt++;        code[i]=ch[code[i]];        st<<=2;        st|=code[i];    }    return st;}bool check(int st,int nst)//判断两种状态能不能转移{    decode(code,N,st);    int flag=0;//标记格子上边是否有插头    int cnt=0;    int k;    for(int i=0;i<N;i++)    {        if(flag==0)//这个格子上边没有插头        {            if(code[i]==0&&(nst&(1<<i))==0)//左边和右边都没有插头               return false;            if(code[i]&&(nst&(1<<i)))continue;            if(code[i])flag=code[i];//插头从左边过来,从下边出去            else flag=-1;//插头从下边进来从右边出去            k=i;        }        else        {            if(code[i]&&(nst&(1<<i)))//左边和右边和上边都有插头               return false;            if(code[i]==0&&(nst&(1<<i))==0)continue;            if(code[i])            {                if(code[i]==flag&&((nst!=0)||i!=N-1))return false;//只有最后一个格子才能合起来                if(flag>0)                {                    for(int j=0;j<N;j++)                      if(code[j]==code[i]&&j!=i)                          code[j]=code[k];                    code[i]=code[k]=0;                }                else                {                    code[k]=code[i];                    code[i]=0;                }            }            else            {                if(flag>0)code[i]=code[k],code[k]=0;                else code[i]=code[k]=N+(cnt++);            }            flag=0;        }    }    if(flag!=0)return false;    return true;}struct Node{    int g[200][200];    int D;}node[20];//打表之用void init(){    if(node[N].D!=0)    {        memcpy(g,node[N].g,sizeof(node[N].g));        D=node[N].D;        return;    }    int st,nst;    hm.init();    memset(code,0,sizeof(code));    code[0]=code[N-1]=1;    hm.push(0);    hm.push(encode(code,N));    memset(g,0,sizeof(g));    for(int i=1;i<hm.size;i++)    {        st=hm.state[i];        for(nst=0;nst<(1<<N);nst++)          if(check(st,nst))          {              int j=hm.push(encode(code,N));              g[i][j]=1;          }    }    D=hm.size;    memcpy(node[N].g,g,sizeof(g));    node[N].D=D;}void solve(){    Matrix temp;    temp.n=temp.m=D;    memcpy(temp.mat,g,sizeof(g));    Matrix ans=pow_M(temp,M);    if(ans.mat[1][0]==0)printf("Impossible\n");    else printf("%d\n",ans.mat[1][0]%MOD);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    for(int i=0;i<20;i++)node[i].D=0;    while(scanf("%d%d",&N,&M)==2)    {        init();        solve();    }    return 0;}
POJ 3133/*POJ 3133连接2的插头为2,连接3的插头为3没有插头为0用四进制表示(四进制比三进制高效)G++ 391ms*/#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>using namespace std;const int MAXD=15;const int HASH=10007;const int STATE=1000010;int N,M;int maze[MAXD][MAXD];//0表示障碍,1是非障碍,2和3int code[MAXD];//0表示没有插头,2表示和插头2相连,3表示和插头3相连struct HASHMAP{    int head[HASH],next[STATE],size;    int state[STATE];    int dp[STATE];    void init()    {        size=0;        memset(head,-1,sizeof(head));    }    void push(int st,int ans)    {        int i,h=st%HASH;        for(i=head[h];i!=-1;i=next[i])          if(state[i]==st)          {              if(dp[i]>ans)dp[i]=ans;              return;          }        state[size]=st;        dp[size]=ans;        next[size]=head[h];        head[h]=size++;    }}hm[2];void decode(int *code,int m,int st)//四进制{    int i;    for(int i=m;i>=0;i--)    {        code[i]=(st&3);        st>>=2;    }}int encode(int *code,int m){    int i;    int st=0;    for(int i=0;i<=m;i++)    {        st<<=2;        st|=code[i];    }    return st;}void shift(int *code,int m)//换行{    for(int i=m;i>0;i--)code[i]=code[i-1];    code[0]=0;}void dpblank(int i,int j,int cur){    int k,left,up;    for(k=0;k<hm[cur].size;k++)    {        decode(code,M,hm[cur].state[k]);        left=code[j-1];        up=code[j];        if(left&&up)        {            if(left==up)//只能是相同的插头            {                code[j-1]=code[j]=0;                if(j==M)shift(code,M);                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }        }        else if((left&&(!up))||((!left)&&up))//只有一个插头        {            int t;            if(left)t=left;            else t=up;//这里少写个else ,查了好久的错误            if(maze[i][j+1]==1||maze[i][j+1]==t)//插头从右边出来            {                code[j-1]=0;                code[j]=t;                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }            if(maze[i+1][j]==1||maze[i+1][j]==t)//插头从下边出来            {                code[j]=0;                code[j-1]=t;                if(j==M)shift(code,M);                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }        }        else if(left==0&&up==0)//没有插头        {            code[j-1]=code[j]=0;//不加插头            if(j==M)shift(code,M);            hm[cur^1].push(encode(code,M),hm[cur].dp[k]);            if(maze[i][j+1]&&maze[i+1][j])            {                if(maze[i][j+1]==1&&maze[i+1][j]==1)                {                    decode(code,M,hm[cur].state[k]);                    code[j-1]=code[j]=2;//加2号插头                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);                    //decode(code,M,hm[cur].state[k]);                    code[j-1]=code[j]=3;//加3号插头                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);                }                else if((maze[i][j+1]==2&&maze[i+1][j]==1)||(maze[i+1][j]==2&&maze[i][j+1]==1)||(maze[i][j+1]==2&&maze[i+1][j]==2))                {                    decode(code,M,hm[cur].state[k]);                    code[j-1]=code[j]=2;                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);                }                else if((maze[i][j+1]==3&&maze[i+1][j]==1)||(maze[i+1][j]==3&&maze[i][j+1]==1)||(maze[i][j+1]==3&&maze[i+1][j]==3))                {                    decode(code,M,hm[cur].state[k]);                    code[j-1]=code[j]=3;                    hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);                }            }        }    }}void dpblock(int i,int j,int cur){    int k;    for(k=0;k<hm[cur].size;k++)    {        decode(code,M,hm[cur].state[k]);        if(code[j-1]!=0||code[j]!=0)continue;        code[j-1]=code[j]=0;//不加插头        if(j==M)shift(code,M);        hm[cur^1].push(encode(code,M),hm[cur].dp[k]);    }}void dp_2(int i,int j,int cur){    int left,up,k;    for(k=0;k<hm[cur].size;k++)    {        decode(code,M,hm[cur].state[k]);        left=code[j-1];        up=code[j];        if((left==2&&up==0)||(left==0&&up==2))        {            code[j-1]=code[j]=0;            if(j==M)shift(code,M);            hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);        }        else if(left==0&&up==0)        {            if(maze[i][j+1]==1||maze[i][j+1]==2)            {                code[j-1]=0;                code[j]=2;                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }            if(maze[i+1][j]==1||maze[i+1][j]==2)            {                code[j-1]=2;                code[j]=0;                if(j==M)shift(code,M);                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }        }    }}void dp_3(int i,int j,int cur){    int left,up,k;    for(k=0;k<hm[cur].size;k++)    {        decode(code,M,hm[cur].state[k]);        left=code[j-1];        up=code[j];        if((left==3&&up==0)||(left==0&&up==3))        {            code[j-1]=code[j]=0;            if(j==M)shift(code,M);            hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);        }        else if(left==0&&up==0)        {            if(maze[i][j+1]==1||maze[i][j+1]==3)            {                code[j-1]=0;                code[j]=3;                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }            if(maze[i+1][j]==1||maze[i+1][j]==3)            {                code[j-1]=3;                code[j]=0;                if(j==M)shift(code,M);                hm[cur^1].push(encode(code,M),hm[cur].dp[k]+1);            }        }    }}void init(){    memset(maze,0,sizeof(maze));    for(int i=1;i<=N;i++)      for(int j=1;j<=M;j++)      {          scanf("%d",&maze[i][j]);          //if(maze[i][j]==0)maze[i][j]=1;          //if(maze[i][j]==1)maze[i][j]=0;          //上面的写法是错的,!!!          if(maze[i][j]==1||maze[i][j]==0)maze[i][j]^=1;//0变1,1变0      }}void solve(){    int i,j,cur=0;    hm[cur].init();    hm[cur].push(0,0);    for(int i=1;i<=N;i++)      for(int j=1;j<=M;j++)      {          hm[cur^1].init();          if(maze[i][j]==0)dpblock(i,j,cur);          else if(maze[i][j]==1)dpblank(i,j,cur);          else if(maze[i][j]==2)dp_2(i,j,cur);          else if(maze[i][j]==3)dp_3(i,j,cur);          cur^=1;      }    int ans=0;    for(int i=0;i<hm[cur].size;i++)      ans+=hm[cur].dp[i];    if(ans>0)ans-=2;    printf("%d\n",ans);}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    while(scanf("%d%d",&N,&M))    {        if(N==0&&M==0)break;        init();        solve();    }    return 0;}

数据结构

后缀数组

k

const int maxn = 2e5+100;const int INF = 0x3f3f3f3f;#define pr(x)       cout << #x << " = " << x << " ";#define prln(x)     cout << #x << " = " << x <<endl;#define rep(i,n) for(int i = 0;i < n; i++) #define ll long long#define MEM(a,b) memset(a,b,sizeof a)#define CLR(a) memset(a,0,sizeof a)#define MN(a,b,n) memset(a,b,n*sizeof(int))int rk[maxn], sa[maxn], height[maxn], w[maxn], wa[maxn], res[maxn];void getSa(int len, int up){    int *k = rk,*id = height, *r = res,*cnt=wa;    rep(i,up) cnt[i] = 0;    rep(i,len) cnt[k[i]=w[i]]++;    rep(i,up) cnt[i+1] += cnt[i];    for(int i = len-1; i >=0; --i){        sa[--cnt[k[i]]] = i;     }    int d = 1, p = 0;    while(p < len) {        for(int i = len-d; i < len;++i) id[p++] = i;        rep(i,len) if(sa[i] >= d) id[p++] = sa[i]-d;        rep(i,len) r[i] = k[id[i]];        rep(i,up) cnt[i] = 0;        rep(i,len) cnt[r[i]]++;        rep(i,up) cnt[i+1] += cnt[i];        for(int i = len-1; i >= 0; --i) {            sa[--cnt[r[i]]] = id[i];        }        swap(k,r);        p = 0;        k[sa[0]] = p++;        rep(i,len-1) {            if(sa[i]+d < len && sa[i+1]+d <len &&r[sa[i]]==r[sa[i+1]]&&r[sa[i]+d]==r[sa[i+1]+d])                k[sa[i+1]] = p-1;            else    k[sa[i+1]] = p++;        }        if(p >= len) return;        d*=2; up = p; p = 0;    }}void getHeight(int len) {    rep(i,len) rk[sa[i]] = i;    height[0] = 0;    for(int i = 0,p=0; i < len-1; ++i) {        int j = sa[rk[i]-1];        while(i+p<len&&j+p<len&&w[i+p]==w[j+p]) p++;        height[rk[i]] = p;        p = max(p-1,0);    }}int getSuffix(int s[],int len) {    int  up = 0;    for(int i = 0; i < len; ++i) {        w[i] = s[i];        up = max(up,w[i]);    }    w[len++] = 0;    getSa(len,up+1);    getHeight(len);    return len;}int n, k;bool ok(int len) {    int i = 2,  cnt;    while(true) {        while(i <= n && height[i] < len) ++i;        if(i > n) return false;        cnt = 1;        while(i <= n && height[i] >= len) {            ++i;            cnt++;        }        if(cnt >= k) return true;    }    return false;}int num[maxn];int main(){#ifdef LOCAL    freopen("C:\\Users\\Administrator\\Desktop\\in.txt","r",stdin);  //freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout); #endif    cin >> n >> k;    rep(i,n) scanf("%d",&num[i]);    getSuffix(num,n);    int l = 0, r= n, mid;    while(l < r) {        mid = (l+r+1)/2;        if(ok(mid)) l = mid;        else r = mid-1;    }    printf("%d\n",l);    return 0;}

AC自动机

在线AC自动机

/*Educational Codeforces Round 16给定N≤3×105次操作,操作一个字符串集合1 s:向集合添加字符串s2 s:从集合删除字符串s3 s:查询字符串s在集合的所有字符串中出现了多少次保证添加和删除操作合法,且∑|S|≤3×105*/const int N = 3e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;struct ACAutomata {    static const int S = 26;    int sz, root;    vector<vector<int> > nxt;    vector<int> fail, cnt;    inline int idx(char c) {return c - 'a';}    inline int newNode() {        cnt.push_back(0);        nxt.push_back(vector<int>(S, 0));        return sz++;    }    void init() {        sz = 0;        nxt.clear();        cnt.clear();        fail.clear();        root = newNode();    }    void insert(const char* s, int d) {        int u = root;        for(; *s; ++s) {            int c = idx(*s);            int& v = nxt[u][c];            if(!v) v = newNode();            u = v;        }        cnt[u] += d;    }    void build() {        vector<int> q;        fail.resize(nxt.size());        fail[root] = root;        for(int i = 0; i < S; ++i) {            int& v = nxt[root][i];            if(v) {                fail[v] = root;                q.push_back(v);            } else v = root;        }        for(int k = 0; k < q.size(); ++k) {            int u = q[k];            for(int i = 0; i < S; ++i) {                int& v = nxt[u][i];                if(v) {                    fail[v] = nxt[fail[u]][i];                    cnt[v] += cnt[nxt[fail[u]][i]];                    q.push_back(v);                } else v = nxt[fail[u]][i];            }        }    }    LL query(const char* s) {        LL ret = 0;        int u = root;        for(; *s; ++s) {            int c = idx(*s);            u = nxt[u][c];            ret += cnt[u];        }        return ret;    }};int q, op[N];string s[N];struct StaticToDynamic {    static const int LOG = 20;    ACAutomata ac[LOG];    vector<int> g[LOG];    void init() {        for(int i = 0; i < LOG; ++i) {            g[i].clear();            ac[i].init();        }    }    inline get(int x) {        return x == 1 ? 1 : -1;    }    void add(int id) {        int p = -1;        for(int i = 0; i < LOG && !~p; ++i) if(g[i].empty()) p = i;        g[p].push_back(id);        ac[p].insert(s[id].c_str(), get(op[id]));        for(int i = 0; i < p; ++i) {            for(int id : g[i]) {                g[p].push_back(id);                ac[p].insert(s[id].c_str(), get(op[id]));            }            g[i].clear();            ac[i].init();        }        ac[p].build();    }    LL query(int id) {        LL ret = 0;        for(int i = 0; i < LOG; ++i) ret += ac[i].query(s[id].c_str());        return ret;    }} solver;int main() {    ios_base::sync_with_stdio(0);    while(cin >> q) {        solver.init();        for(int i = 1; i <= q; ++i) {            cin >> op[i] >> s[i];            if(op[i] <= 2) {                solver.add(i);            } else {                cout << solver.query(i) << endl;            }        }    }    return 0;}

回文树

/*************************************************************************hdu5785给定N≤106的字符串,现在寻找所有三元组(i, j, k),1≤i≤j<k≤N使得s[i…j]和s[j+1…k]都是回文串,求∑∑i×k mod 109+7 ************************************************************************/#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<stack>#include<map>#include<set>#include<vector>#include<queue>#include<string>#include<cmath>using namespace std;#define ll long long#define rep(i,n) for(int i =0; i < n; ++i)#define CLR(x) memset(x,0,sizeof x)#define MEM(a,b) memset(a,b,sizeof a)#define pr(x) cout << #x << " = " << x << " ";#define prln(x) cout << #x << " = " << x <<  endl; const int maxn = 1e6+100;const int INF = 0x3f3f3f3f;const int N = 27;typedef pair<int,int> P;const int MOD = 1e9+7;struct Pstree{    int nxt[maxn][26];    int fail[maxn];    int num[maxn];    int len[maxn];    int ans[maxn];    char s[maxn];    int last, n, p;    int newnode(int x){        for(int i = 0; i < N; ++i){            nxt[p][i] = 0;        }        len[p] = x;        num[p] = 0;        ans[p] = 0;        return p++;    }    void init(){        p = 0;        n = 0;        last = 0;        newnode(0);        newnode(-1);        s[n] = 255;         fail[0] = 1;    }    int getfail(int x){        while(s[n-len[x]-1] != s[n]) x = fail[x];        return x;    }    P add(int c){        c -= 'a';        s[++n] = c;        int cur =  getfail(last);        if(!nxt[cur][c]){            int now = newnode(len[cur]+2);            fail[now] = nxt[getfail(fail[cur])][c];            nxt[cur][c] = now;            num[now] =  num[fail[now]] + 1;            ans[now] = ans[fail[now]] + len[cur]+2;            ans[now] %= MOD;        }        last = nxt[cur][c];        return P(num[last], ans[last]);    }}pstree;char s[maxn];int lnum[maxn];int lans[maxn];int main(){    int n;    while(scanf("%s", s) != EOF){        n = strlen(s);        pstree.init();        for(int i = 0; i < n; ++i){            P ans = pstree.add(s[i]);            lnum[i+1] = ans.first;            lans[i+1] = ans.second;        }        pstree.init();        ll cnt = 0;        for(int i = n-1; i > 0; --i){            P ans = pstree.add(s[i]);            cnt += ((ll)(i+1)*lnum[i] - (ll)lans[i])%MOD*((ll)((ll)i*ans.first%MOD) + ans.second)%MOD;            cnt %= MOD;        }        cnt = (cnt%MOD+MOD)%MOD;        printf("%lld\n", cnt);    }    return 0;}
  • N≤103的字符串,Q≤105次询问

  • 每次询问[l, r]区间本质不同的回文子串有几个,即不完全相同的回文子串

/*hdu5658*/const int N = 1e3 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;// last:= 指向添加一个字符后形成的最长回文串的节点// s[i]:= 第 i 次添加的字符 n:= s 数组时针// fail[i]:= i 失配后跳转到的 i 表示的最长回文串的最长真后缀回文串的节点// cnt[i]:= 以 i 表示的最长回文串的右端点为右端点的回文串个数// dif[i]:= i 表示的本质不同的回文串个数 (需要重新统计)struct PalindromicTree {    static const int M = 1e3 + 10, S = 26;    int n, sz, last;    int nxt[M][S], fail[M], len[M], s[M];    int cnt[M], dif[M];    int newNode(int l) {        len[sz] = l;        cnt[sz] = dif[sz] = 0;        memset(nxt[sz], 0, sizeof nxt[sz]);        return sz++;    }    void init() {        sz = last = 0;        newNode(0); newNode(-1);        s[n = 0] = -1; // 无关字符减少特判        fail[0] = 1;    }    int getFail(int u) {        while(s[n - len[u] - 1] != s[n]) u = fail[u];        return u;    }    void add(int c) {        s[++n] = c;        int u = getFail(last); // 找到这个回文串的匹配位置        int& v = nxt[u][c];        if(!v) {            int cur = newNode(len[u] + 2);            fail[cur] = nxt[getFail(fail[u])][c];            v = cur;            cnt[v] = cnt[fail[v]] + 1;        }        ++dif[v];        last = v;    }    void count() {        //父亲累加儿子,如果 fail[v]=u ,则 u 一定是 v 的子回文串        for(int i = sz - 1; ~i; --i) dif[fail[i]] += dif[i];    }} pt;int n, q;char a[N];int ans[N][N];int main() {    ios_base::sync_with_stdio(0);    int t; scanf("%d", &t);    while(t--) {        scanf("%s", a + 1);        n = strlen(a + 1);        for(int i = 1; i <= n; ++i) {            pt.init();            for(int j = i; j <= n; ++j) {                pt.add(a[j] - 'a');                ans[i][j] = pt.sz - 2;            }        }        scanf("%d", &q);        while(q--) {            int l, r; scanf("%d%d", &l, &r);            printf("%d\n", ans[l][r]);        }    }    return 0;}

主席树

标记永久化

  • 给定N≤105个数,Q≤105询问,简而言之就是对某个版本进行区间更新区间查询
onst int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, q;typedef long long LL;int root[N];struct PersistentSegTree {    static const int M = 1e5 * 30;    int sz;    struct Node {        int ls, rs, add;        LL sum;    } tree[M];    void init() {        sz = 0;        memset(&tree[0], 0, sizeof tree[0]);    }    int newNode(int rt) {        tree[++sz] = tree[rt];        return sz;    }    void up(int rt) {        tree[rt].sum = tree[tree[rt].ls].sum + tree[tree[rt].rs].sum;    }    void build(int l, int r, int& rt) {        rt = newNode(0);        if(l == r) {            scanf("%I64d", &tree[rt].sum);            return;        }        int m = l + r >> 1;        build(l, m, tree[rt].ls);        build(m + 1, r, tree[rt].rs);        up(rt);    }    void show(int l, int r, int rt) {        pr("show"); pr(rt); pr(l); pr(r); pr(tree[rt].add); prln(tree[rt].sum);        if(l == r) return ;        int m = l + r >> 1;        show(l, m, tree[rt].ls);        show(m + 1, r, tree[rt].rs);    }    void update(int L, int R, int v, int l, int r, int& rt) {        rt = newNode(rt);        tree[rt].sum += v * (min(r, R) - max(l, L) + 1);        if(L <= l && r <= R) {            tree[rt].add += v;            return;        }        int m = l + r >> 1;        if(L <= m) update(L, R, v, l, m, tree[rt].ls);        if(R > m) update(L, R, v, m + 1, r, tree[rt].rs);    }    LL query(int L, int R, int l, int r, int rt) {        if(L <= l && r <= R) return tree[rt].sum;        LL ret = 1LL * tree[rt].add * (min(r, R) - max(l, L) + 1);        int m = l + r >> 1;        if(L <= m) ret += query(L, R, l, m, tree[rt].ls);        if(R > m) ret += query(L, R, m + 1, r, tree[rt].rs);        return ret;    }} T;int main() {    ios_base::sync_with_stdio(0);    while(scanf("%d%d", &n, &q) == 2) {        T.init();        T.build(1, n, root[0]);        int timStp = 0;        while(q--) {            char op[2]; scanf("%s", op);            if(*op == 'C') {                int l, r, d; scanf("%d%d%d", &l, &r, &d);                ++timStp;                root[timStp] = root[timStp - 1];//                T.show(1, n, root[timStp]);                T.update(l, r, d, 1, n, root[timStp]);            } else if(*op == 'Q') {                int l, r; scanf("%d%d", &l, &r);                printf("%I64d\n", T.query(l, r, 1, n, root[timStp]));            } else if(*op == 'H') {                int l, r, t; scanf("%d%d%d", &l, &r, &t);                printf("%I64d\n", T.query(l, r, 1, n, root[t]));            } else {                scanf("%d", &timStp);            }        }    }    return 0;}

prefix字典树 hdu5790

  • N≤105个字符串,保证∑|Li|≤105,Q≤105次询问在线查询[L, R]区间有多少个不同的前缀
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, q;char s[N];int root[N];struct PersistentSegTree {    static const int M = 1e5 * 40;    int sz;    struct Node {        int ls, rs, sum;    } tree[M];    void init() {        sz = 0;        root[0] = 0;    }    int newNode(int rt) {        tree[++sz] = tree[rt];        return sz;    }    void update(int o, int v, int l, int r, int& rt) {        rt = newNode(rt);        tree[rt].sum += v;        if(l == r) return;        int m = l + r >> 1;        if(o <= m) update(o, v, l, m, tree[rt].ls);        else update(o, v, m + 1, r, tree[rt].rs);    }    int query(int L, int R, int l, int r, int rt) {        if(L <= l && r <= R) return tree[rt].sum;        int m = l + r >> 1, ret = 0;        if(L <= m) ret += query(L, R, l, m, tree[rt].ls);        if(R > m) ret += query(L, R, m + 1, r, tree[rt].rs);        return ret;    }} T;struct Trie {    static const int M = 1e5 + 10, S = 26;    int sz, rt, nxt[M][S];    int val[M];    int newNode() {        val[sz] = 0;        memset(nxt[sz], 0, sizeof nxt[sz]);        return sz++;    }    void init() {        sz = 0;        rt = newNode();    }    void insert(char* s, int id) {        int u = rt;        for(int i = 0; s[i]; ++i) {            int& v = nxt[u][s[i] - 'a'];            if(!v) v = newNode();            if(val[v]) T.update(val[v], -1, 1, n, root[id]);            val[v] = id;            T.update(val[v], 1, 1, n, root[id]);            u = v;        }    }} trie;int main() {    ios_base::sync_with_stdio(0);    while(scanf("%d", &n) == 1) {        T.init();        trie.init();        for(int i = 1; i <= n; ++i) {            scanf("%s", s);            root[i] = root[i - 1];            trie.insert(s, i);        }        int z = 0;        scanf("%d", &q);        while(q--) {            int l, r; scanf("%d%d", &l, &r);            l = (z + l) % n + 1;            r = (z + r) % n + 1;            if(l > r) swap(l, r);            z = T.query(l, n, 1, n, root[r]);            printf("%d\n", z);        }    }    return 0;}

二叉搜索树

nlogn建树+kmp

N6×1051N
10101
T|T|7000

const int N = 6e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, m;int rt, ls[N], rs[N];char s[N << 1], t[7010];void dfs(int rt) {    s[n++] = (rt & 1) + '0';    if(ls[rt]) {        dfs(ls[rt]);        s[n++] = (rt & 1) + '0';    }    if(rs[rt]) {        dfs(rs[rt]);        s[n++] = (rt & 1) + '0';    }}int kmp() {    m = strlen(t);    vector<int> nxt(m + 1);    nxt[0] = -1;    for(int i = 0, j = -1; i < m;) {        if(j == -1 || t[i] == t[j]) nxt[++i] = ++j;        else j = nxt[j];    }    int ret = 0;    for(int i = 0, j = 0; i < n;) {        if(j == -1 || s[i] == t[j]) ++i, ++j;        else j = nxt[j];        if(j == m) {            ++ret;            j = nxt[j];        }    }    return ret;}int main() {    ios_base::sync_with_stdio(0);    int T; scanf("%d", &T);    while(T--) {        scanf("%d", &n);        memset(ls, 0, sizeof ls);        memset(rs, 0, sizeof rs);        set<int> st;        for(int i = 1; i <= n; ++i) {            int x; scanf("%d", &x);            if(!st.size()) rt = x;            else {                auto it = st.lower_bound(x);                if(it == st.end()) rs[*--it] = x;                else {                    if(!ls[*it]) ls[*it] = x;                    else rs[*--it] = x;                }            }            st.insert(x);        }        scanf("%s", t);        n = 0;        dfs(rt);        s[n] = 0;        static int kase = 0;        printf("Case #%d: %d\n", ++kase, kmp());    }    return 0;}

可持久化Trie

HDU 5801 Up Sky,Mr.Zhu

N105S5<20
str[0n1]str[n/2n1]
s[LR]T|T|10

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;int root[N];struct PersistentTrie {    static const int M = N * 10, S = 5;    int sz;    struct Node {        LL val;        int nxt[S];    } dat[M];    void init() {        sz = 0;        memset(&dat[0], 0, sizeof dat[0]);    }    int newNode(int rt) {        dat[++sz] = dat[rt];        return sz;    }    void update(char* s, int n, int& rt) {        rt = newNode(rt);        int u = rt;        for(int i = 0; i < n; ++i) {            int c = s[i] - 'a';            int& v = dat[u].nxt[c];            v = newNode(v);            ++dat[v].val;            u = v;        }    }    LL query(char* s, int rt) {        int u = rt;        for(int i = 0; s[i]; ++i) {            int c = s[i] - 'a';            u = dat[u].nxt[c];        }        return dat[u].val;    }} trie;int q;char s[N], t[N][15];int l[N], r[N];LL ans[N];bool check(char* s, int len) {    for(int i = 0; i < len / 2; ++i)        if(s[-i] != s[-(len - i - 1)]) return false;    return true;}int main() {    ios_base::sync_with_stdio(0);    while(scanf("%s%d", s + 1, &q) == 2) {        int n = strlen(s + 1);        for(int i = 1; i <= q; ++i) scanf("%d%d%s", l + i, r + i, t[i]);        memset(ans, 0, sizeof ans);        for(int len = 1; len < 20; ++len) {            trie.init();            for(int i = 1; i <= n; ++i) {                root[i] = root[i - 1];                if(i < len) continue;                bool ok = check(s + i, len);                if(!ok) continue;                int l = i - (len - 1) / 2;                trie.update(s + l, (len + 1) / 2, root[i]);            }            for(int i = 1; i <= q; ++i) {                if(r[i] - l[i] + 1 < len) continue;                ans[i] += trie.query(t[i], root[r[i]]) - trie.query(t[i], root[l[i] + len - 2]);            }        }        for(int i = 1; i <= q; ++i)            printf("%I64d\n", ans[i]);    }    return 0;}

树上莫队

SPOJ Count on a tree II(树上莫队)

N40000Ai109
Q105(u,v)

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;const int B = 200;int n, m, a[N], b[N];struct Edge {    int v, nxt;} edge[N << 1];int head[N], eCnt;void addEdge(int u, int v) {    edge[eCnt] = {v, head[u]};    head[u] = eCnt++;}int L[N], R[N], dep[N], fa[N], vs[N], dfsNum;int id[N], blocks;int stk[N], top;void dfs(int u, int f) {    L[u] = ++dfsNum;    vs[dfsNum] = u;    fa[u] = f;    int btm = top;    for(int i = head[u]; ~i; i = edge[i].nxt) {        int v = edge[i].v;        if(v == f) continue;        dep[v] = dep[u] + 1;        dfs(v, u);        if(top - btm >= B) {            ++blocks;            while(top != btm) {                int v = stk[top--];                id[v] = blocks;            }        }    }    R[u] = dfsNum;    stk[++top] = u;}struct Query {    int l, r, id;};bool cmpTree(const Query& a, const Query& b) {    return id[a.l] < id[b.l] ||           id[a.l] == id[b.l] && L[a.r] < L[b.r];}int cnt[N];int sum, ans[N];void add(int x) {    if(cnt[b[x]]++ == 0) ++sum;}void del(int x) {    if(--cnt[b[x]] == 0) --sum;}bool in[N];int cross;void reverse(int x) {    if(in[x]) {        in[x] = false;        del(x);    } else {        in[x] = true;        add(x);    }}void moveUp(int& x) {    if(!cross) {        if(in[x] && !in[fa[x]]) cross = x;        else if(in[fa[x]] && !in[x]) cross = fa[x];    }    reverse(x); x = fa[x];}void move(int a, int b) {    if(a == b) return;    cross = 0;    if(in[b]) cross = b;    while(dep[a] > dep[b]) moveUp(a);    while(dep[b] > dep[a]) moveUp(b);    while(a != b) moveUp(a), moveUp(b);    reverse(a); reverse(cross);}void gao() {    dfsNum = blocks = 0;    dfs(1, 0);    while(top) id[stk[top--]] = blocks;}int main() {    ios_base::sync_with_stdio(0);    scanf("%d%d", &n, &m);    vector<int> xs(n);    for(int i = 1; i <= n; ++i) {        scanf("%d", a + i);        xs[i - 1] = a[i];    }    sort(xs.begin(), xs.end());    xs.resize(unique(xs.begin(), xs.end()) - xs.begin());    for(int i = 1; i <= n; ++i)        b[i] = lower_bound(xs.begin(), xs.end(), a[i]) - xs.begin() + 1;    eCnt = 0; memset(head, -1, sizeof head);    for(int i = 1; i < n; ++i) {        int u, v; scanf("%d%d", &u, &v);        addEdge(u, v);        addEdge(v, u);    }    gao();    vector<Query> qt(m);    for(int i = 1; i <= m; ++i) {        int u, v; scanf("%d%d", &u, &v);        if(id[u] > id[v]) swap(u, v);        qt[i - 1] = {u, v, i};    }    sort(qt.begin(), qt.end(), cmpTree);    sum = 0;    memset(cnt, 0, sizeof cnt);    memset(in, 0, sizeof in);    add(1); in[1] = true;    int l = 1, r = 0;    for(auto& q : qt) {        move(l, q.l);        move(r, q.r);        l = q.l; r = q.r;        ans[q.id] = sum;    }    for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);    return 0;}

HDU 5799 This world need more Zhu(树上莫队)

N105Ai109Q105opuvab
op=1u=vugcd(cnt[x]=ax,cnt[y]=by)
op=2(u,v)gcd(cnt[x]=ax,cnt[y]=by)

/*op=1,dfs序搞成序列上的莫队,op=2树上莫队*/const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;const int B = 250;typedef long long LL;int n, m, a[N], b[N];struct Edge {    int v, nxt;} edge[N << 1];int head[N], eCnt;void addEdge(int u, int v) {    edge[eCnt] = {v, head[u]};    head[u] = eCnt++;}int L[N], R[N], dep[N], fa[N], vs[N], dfsNum;int id[N], blocks;int stk[N], top;void dfs(int u, int f) {    L[u] = ++dfsNum;    vs[dfsNum] = u;    fa[u] = f;    int btm = top;    for(int i = head[u]; ~i; i = edge[i].nxt) {        int v = edge[i].v;        if(v == f) continue;        dep[v] = dep[u] + 1;        dfs(v, u);        if(top - btm >= B) {            ++blocks;            while(top != btm) {                int v = stk[top--];                id[v] = blocks;            }        }    }    R[u] = dfsNum;    stk[++top] = u;}struct Query {    int l, r, block, a, b, id;};bool cmpSeq(const Query& a, const Query& b) {    return a.block < b.block ||           a.block == b.block && a.r < b.r;}bool cmpTree(const Query& a, const Query& b) {    return id[a.l] < id[b.l] ||           id[a.l] == id[b.l] && L[a.r] < L[b.r];}int cnt[N];LL sum[N], ans[N];void add(int x) {    sum[cnt[b[x]]] -= a[x];    ++cnt[b[x]];    sum[cnt[b[x]]] += a[x];}void del(int x) {    sum[cnt[b[x]]] -= a[x];    --cnt[b[x]];    sum[cnt[b[x]]] += a[x];}bool in[N];int cross;void reverse(int x) {    if(in[x]) {        in[x] = false;        del(x);    } else {        in[x] = true;        add(x);    }}void moveUp(int& x) {    if(!cross) {        if(in[x] && !in[fa[x]]) cross = x;        else if(in[fa[x]] && !in[x]) cross = fa[x];    }    reverse(x); x = fa[x];}void move(int a, int b) {    if(a == b) return;    cross = 0;    if(in[b]) cross = b;    while(dep[a] > dep[b]) moveUp(a);    while(dep[b] > dep[a]) moveUp(b);    while(a != b) moveUp(a), moveUp(b);    reverse(a); reverse(cross);}void gao() {    dfsNum = blocks = 0;    dfs(1, 0);    while(top) id[stk[top--]] = blocks;}int main() {    ios_base::sync_with_stdio(0);    int t; scanf("%d", &t);    while(t--) {        scanf("%d%d", &n, &m);        vector<int> xs(n);        for(int i = 1; i <= n; ++i) {            scanf("%d", a + i);            xs[i - 1] = a[i];        }        sort(xs.begin(), xs.end());        xs.resize(unique(xs.begin(), xs.end()) - xs.begin());        for(int i = 1; i <= n; ++i)            b[i] = lower_bound(xs.begin(), xs.end(), a[i]) - xs.begin() + 1;        eCnt = 0; memset(head, -1, sizeof head);        for(int i = 1; i < n; ++i) {            int u, v; scanf("%d%d", &u, &v);            addEdge(u, v);            addEdge(v, u);        }        gao();        vector<Query> qs, qt;        for(int i = 1; i <= m; ++i) {            int op, u, v, a, b;            scanf("%d%d%d%d%d", &op, &u, &v, &a, &b);            if(op == 1) {                int p = L[u] / B;                qs.push_back({L[u], R[u], p, a, b, i});            } else {                if(id[u] > id[v]) swap(u, v);                qt.push_back({u, v, -1, a, b, i});            }        }        {            //subtree            sort(qs.begin(), qs.end(), cmpSeq);            memset(cnt, 0, sizeof cnt);            memset(sum, 0, sizeof sum);            int l = 1, r = 0;            for(auto& q : qs) {                while(r < q.r) add(vs[++r]);                while(l < q.l) del(vs[l++]);                while(r > q.r) del(vs[r--]);                while(l > q.l) add(vs[--l]);                ans[q.id] = __gcd(sum[q.a], sum[q.b]);            }        }        {            //path            sort(qt.begin(), qt.end(), cmpTree);            memset(cnt, 0, sizeof cnt);            memset(sum, 0, sizeof sum);            memset(in, 0, sizeof in);            add(1); in[1] = true;            int l = 1, r = 0;            for(auto& q : qt) {                move(l, q.l);                move(r, q.r);                l = q.l; r = q.r;                ans[q.id] = __gcd(sum[q.a], sum[q.b]);            }        }        static int kase = 0;        printf("Case #%d:\n", ++kase);        for(int i = 1; i <= m; ++i) printf("%I64d\n", ans[i]);    }    return 0;}

线段树

AOJ 2450 Do use segment tree (树链剖分 + 线段树区间合并)

N<=2×105,Q<=105,
1uvc,u>vc
2uvc,u>v,c

const int N = 2e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, q, w[N], val[N];struct Node {    int l, r;    int pre, suf, sub, sum;    Node() {pre = suf = sub = sum = -INF;}    Node rev() {        Node ret = *this;        swap(ret.pre, ret.suf);        return ret;    }    void set(int v) {        sum = v * (r - l + 1);        pre = suf = sub = max(v, sum);    }};void printNode(Node x) {    printf("l: %d r: %d pre: %d suf: %d sub: %d sum: %d\n",           x.l, x.r, x.pre, x.suf, x.sub, x.sum);}Node operator+ (const Node& A, const Node& B) {    if(A.sub == -INF) return B;    if(B.sub == -INF) return A;    Node ret; ret.l = A.l, ret.r = B.r;    ret.sum = A.sum + B.sum;    ret.pre = max(A.pre, A.sum + B.pre);    ret.suf = max(B.suf, B.sum + A.suf);    ret.sub = max(A.suf + B.pre, max(A.sub, B.sub));    return ret;}struct SegTree {    Node dat[N << 2];    int setv[N << 2];    void push_up(int rt) {        dat[rt] = dat[rt << 1] + dat[rt << 1 | 1];    }    void push_down(int rt) {        if(setv[rt] != -INF) {            int v = setv[rt], ls = rt << 1, rs = ls | 1;            setv[ls] = setv[rs] = v;            dat[ls].set(v);            dat[rs].set(v);            setv[rt] = -INF;        }    }    void build(int l, int r, int rt) {        setv[rt] = -INF;        if(l == r) {            dat[rt].l = l, dat[rt].r = r;            dat[rt].set(val[l]);            return;        }        int m = l + r >> 1;        build(l, m, rt << 1);        build(m + 1, r, rt << 1 | 1);        push_up(rt);    }    void update(int L, int R, int v, int rt) {        if(L <= dat[rt].l && dat[rt].r <= R) {            setv[rt] = v;            dat[rt].set(v);            return;        }        push_down(rt);        int m = dat[rt].l + dat[rt].r >> 1;        if(L <= m) update(L, R, v, rt << 1);        if(R > m) update(L, R, v, rt << 1 | 1);        push_up(rt);    }    void printAll(int rt) {        printNode(dat[rt]);        if(dat[rt].l == dat[rt].r) return;        printAll(rt << 1);        printAll(rt << 1 | 1);    }    Node query(int L, int R, int rt) {        if(L <= dat[rt].l && dat[rt].r <= R) return dat[rt];        push_down(rt);        int m = dat[rt].l + dat[rt].r >> 1;        Node ret;        if(L <= m && R > m) ret = query(L, R, rt << 1) + query(L, R, rt << 1 | 1);        else if(L <= m) ret = query(L, R, rt << 1);        else if(R > m) ret = query(L, R, rt << 1 | 1);        return ret;    }};struct Edge {    int to, nxt;};struct HLD {    int head[N], cnt, tid;    int sz[N], son[N], fa[N], dep[N], top[N], dfn[N];    Edge edge[N << 1];    SegTree T;    void init() {        cnt = tid = 0;        memset(head, -1, sizeof head);        memset(son, 0, sizeof son);    }    void add_edge(int u, int v) {        edge[cnt] = (Edge) {v, head[u]};        head[u] = cnt++;        edge[cnt] = (Edge) {u, head[v]};        head[v] = cnt++;    }    //find heavy edge    void dfs1(int u, int f, int d) {        sz[u] = 1, fa[u] = f, dep[u] = d;        for(int i = head[u]; ~i; i = edge[i].nxt) {            int v = edge[i].to;            if(v == f) continue;            dfs1(v, u, d + 1);            if(!son[u] || sz[v] > sz[son[u]]) son[u] = v;            sz[u] += sz[v];        }    }    //connect heavy edge    void dfs2(int u, int tp) {        dfn[u] = ++tid;        val[tid] = w[u];        top[u] = tp;        if(son[u]) dfs2(son[u], tp);        for(int i = head[u]; ~i; i = edge[i].nxt) {            int v = edge[i].to;            if(v == fa[u] || v == son[u]) continue;            dfs2(v, v);        }    }    void update(int u, int v, int c) {        int fu = top[u], fv = top[v];        while(fu != fv) {            if(dep[fu] < dep[fv]) {                swap(u, v);                swap(fu, fv);            }            T.update(dfn[fu], dfn[u], c, 1);            u = fa[fu];            fu = top[u];        }        if(dep[u] > dep[v]) swap(u, v);        T.update(dfn[u], dfn[v], c, 1);    }    int query(int u, int v) {        Node L, R;  //there [l,r] info doesn't matter        int fu = top[u], fv = top[v];        while(fu != fv) {            if(dep[fu] > dep[fv]) {                L = L + T.query(dfn[fu], dfn[u], 1).rev();                u = fa[fu], fu = top[u];            } else {                R = T.query(dfn[fv], dfn[v], 1) + R;                v = fa[fv], fv = top[v];            }        }        if(dep[u] > dep[v]) L = L + T.query(dfn[v], dfn[u], 1).rev();        else R = T.query(dfn[u], dfn[v], 1) + R;        return (L + R).sub;    }    void build() {        dfs1(1, -1, 0);        dfs2(1, 1);        T.build(1, n, 1);    }};HLD hld;int main() {    while(scanf("%d%d", &n, &q) == 2) {        hld.init();        for(int i = 1; i <= n; ++i) scanf("%d", w + i);        for(int i = 1; i < n; ++i) {            int u, v; scanf("%d%d", &u, &v);            hld.add_edge(u, v);        }        hld.build();        while(q--) {            int op, x, y, z; scanf("%d%d%d%d", &op, &x, &y, &z);            if(op == 1) hld.update(x, y, z);            else printf("%d\n", hld.query(x, y));        }    }    return 0;}

HDU 5737 Differencia(归并树)

N105ABAiBi109
Q3×1062
+lrx:A[l,r]x
?lr:[l,r]AiBi

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, q, A, B;int a[N], b[N];int rnd(int& last, int& a, int& b) {    int C = ~(1 << 31), M = (1 << 16) - 1;    a = (36969 + (last >> 3)) * (a & M) + (a >> 16);    b = (18000 + (last >> 3)) * (b & M) + (b >> 16);    return (C & ((a << 16) + b)) % 1000000000;}namespace Discretization {    vector<int> xs;    void init() {        xs = vector<int>(b + 1, b + 1 + n);        sort(xs.begin(), xs.end());        for(int i = 1; i <= n; ++i) {            b[i] = lower_bound(xs.begin(), xs.end(), b[i]) - xs.begin() + 1;            a[i] = upper_bound(xs.begin(), xs.end(), a[i]) - xs.begin();        }    }    int get(int x) {        return upper_bound(xs.begin(), xs.end(), x) - xs.begin();    }}namespace Allocator {    int data[N << 6], *p;    void init() {        p = data;    }    int* allocate(int len) {        p += len;        return p - len;    }}struct Node {    int* indexLeft, *indexRight;    int tag, sum;    void setTag(int v) {        tag = sum = v;    }    int goLeft(int v) {        if(v) return indexLeft[v];        return 0;    }    int goRight(int v) {        if(v) return indexRight[v];        return 0;    }} tree[N << 2];void pushUp(int rt) {    tree[rt].sum = tree[rt << 1].sum + tree[rt << 1 | 1].sum;}void pushDown(int rt) {    if(~tree[rt].tag) {        int v = tree[rt].tag;        int ls = rt << 1, rs = ls | 1;        tree[ls].setTag(tree[rt].goLeft(v));        tree[rs].setTag(tree[rt].goRight(v));        tree[rt].tag = -1;    }}void merge(int rt, int l, int r) {    static int tmp[N];    int m = l + r >> 1;    int* vl = b + l - 1, *vr = b + m;    int sl = m - l + 1, sr = r - m;    int i = 1, j = 1, k = 1;    while(i <= sl && j <= sr) {        if(vl[i] < vr[j]) {            tree[rt].indexLeft[k] = i;            tree[rt].indexRight[k] = j - 1;            tmp[k++] = vl[i++];        } else {            tree[rt].indexLeft[k] = i - 1;            tree[rt].indexRight[k] = j;            tmp[k++] = vr[j++];        }    }    while(i <= sl) {        tree[rt].indexLeft[k] = i;        tree[rt].indexRight[k] = j - 1;        tmp[k++] = vl[i++];    }    while(j <= sr) {        tree[rt].indexLeft[k] = i - 1;        tree[rt].indexRight[k] = j;        tmp[k++] = vr[j++];    }    memcpy(b + l, tmp + 1, r - l + 1 << 2);}void build(int l, int r, int rt) {    tree[rt].tag = -1;    tree[rt].indexLeft = Allocator::allocate(r - l + 1);    tree[rt].indexRight = Allocator::allocate(r - l + 1);    if(l == r) {        tree[rt].sum = a[l] >= b[l];        return;    }    int m = l + r >> 1;    build(l, m, rt << 1);    build(m + 1, r, rt << 1 | 1);    pushUp(rt);    merge(rt, l, r);}void update(int L, int R, int v, int l, int r, int rt) {    if(L <= l && r <= R) {        tree[rt].setTag(v);        return;    }    int m = l + r >> 1;    pushDown(rt);    if(L <= m) update(L, R, tree[rt].goLeft(v), l, m, rt << 1);    if(R > m) update(L, R, tree[rt].goRight(v), m + 1, r, rt << 1 | 1);    pushUp(rt);}int query(int L, int R, int l, int r, int rt) {    if(L <= l && r <= R) return tree[rt].sum;    int m = l + r >> 1, ret = 0;    pushDown(rt);    if(L <= m) ret += query(L, R, l, m, rt << 1);    if(R > m) ret += query(L, R, m + 1, r, rt << 1 | 1);    return ret;}int main() {    ios_base::sync_with_stdio(0);    clock_t _ = clock();    int t; scanf("%d", &t);    while(t--) {        scanf("%d%d%d%d", &n, &q, &A, &B);        for(int i = 1; i <= n; ++i) scanf("%d", a + i);        for(int i = 1; i <= n; ++i) scanf("%d", b + i);        Allocator::init();        Discretization::init();        build(1, n, 1);        int ans = 0, last = 0;        for(int i = 1; i <= q; ++i) {            int l = rnd(last, A, B) % n + 1;            int r = rnd(last, A, B) % n + 1;            int x = rnd(last, A, B) + 1;            if(l > r) swap(l, r);            if(l + r + x & 1) {                x = Discretization::get(x);//                printf("+ %d %d %d\n", l, r, x);                update(l, r, x, 1, n, 1);            } else {                last = query(l, r, 1, n, 1);//                printf("? %d %d ans = %d\n", l, r, last);                ans += 1LL * i * last % MOD;                if(ans >= MOD) ans -= MOD;            }        }        printf("%d\n", ans);    }#ifdef LOCAL    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);#endif    return 0;}

UVA 11402 Ahoy, Pirates!(线段树标记合并)

Fab[a,b]1
Eab[a,b]0
Iab[a,b]010110
Sab[a,b]1

const int N = 1.1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;string str;struct Node {    int l, r;    int sum;    Node() {}    Node(int l, int r): l(l), r(r) {}    int len() {        return r - l + 1;    }    void set(int v) {        if(v == -1) return;        if(v == 2) sum = len() - sum;        else sum = len() * v;    }} dat[N << 2];int tag[N << 2];void pushUp(int rt) {    dat[rt].sum = dat[rt << 1].sum + dat[rt << 1 | 1].sum;}void combineTag(int fa, int& son) {    if(fa == 2) {        if(son == -1) son = 2;        else if(son == 2) son = -1;        else son ^= 1; // switch 0, 1    } else son = fa; //set 0, 1}void pushDown(int rt) {    if(tag[rt] == -1) return;    int ls = rt << 1, rs = ls | 1;    dat[ls].set(tag[rt]);    dat[rs].set(tag[rt]);    combineTag(tag[rt], tag[ls]);    combineTag(tag[rt], tag[rs]);    tag[rt] = -1;}void build(int l, int r, int rt) {    dat[rt] = Node(l, r);    tag[rt] = -1;    if(l == r) {        dat[rt].sum = str[l] - '0';        return;    }    int m = l + r >> 1;    build(l, m, rt << 1);    build(m + 1, r, rt << 1 | 1);    pushUp(rt);}void update(int L, int R, int v, int rt) {    if(L <= dat[rt].l && dat[rt].r <= R) {        dat[rt].set(v);        combineTag(v, tag[rt]);        return;    }    pushDown(rt);    int m = dat[rt].l + dat[rt].r >> 1;    if(L <= m) update(L, R, v, rt << 1);    if(R > m) update(L, R, v, rt << 1 | 1);    pushUp(rt);}int query(int L, int R, int rt) {    if(L <= dat[rt].l && dat[rt].r <= R) return dat[rt].sum;    pushDown(rt);    int m = dat[rt].l + dat[rt].r >> 1;    int ret = 0;    if(L <= m) ret += query(L, R, rt << 1);    if(R > m) ret += query(L, R, rt << 1 | 1);    return ret;}int main() {    ios_base::sync_with_stdio(0);    int t; scanf("%d", &t);    while(t--) {        str.clear();        int m; scanf("%d", &m);        while(m--) {            int cnt;            char buf[105]; scanf("%d%s", &cnt, buf);            while(cnt--) str += buf;        }        build(0, str.size() - 1, 1);        int q; scanf("%d", &q);        int qs = 0;        static int kase = 0;        printf("Case %d:\n", ++kase);        while(q--) {            char op[2]; int a, b; scanf("%s%d%d", op, &a, &b);            if(*op == 'F') update(a, b, 1, 1);            else if(*op == 'E') update(a, b, 0, 1);            else if(*op == 'I') update(a, b, 2, 1);            else printf("Q%d: %d\n", ++qs, query(a, b, 1));        }    }    return 0;}

POJ 3168 Barn Expansion(扫描线)

N2.5×104

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n;int bx[N], by[N], ux[N], uy[N];struct Line {    int x, y, id;    Line() {}    Line(int x, int y, int id): x(x), y(y), id(id) {}    bool operator<(const Line& l) const {        if(x == l.x) {            if(y == l.y) return id < l.id; //+ first            return y < l.y;        }        return x < l.x;    }};void solve(vector<int>& bad, int* bx, int* ux, int* by, int* uy) {    vector<Line> events;    for(int i = 1; i <= n; ++i) {        events.push_back(Line(bx[i], by[i], -i));        events.push_back(Line(bx[i], uy[i], i));        events.push_back(Line(ux[i], by[i], -i));        events.push_back(Line(ux[i], uy[i], i));    }    sort(events.begin(), events.end());    int sum = 1;    for(int i = 1; i < events.size(); ++i) {        sum += events[i].id < 0 ? 1 : -1;        int preID = abs(events[i - 1].id), curID = abs(events[i].id);        if(sum >= 2) bad[preID] = bad[curID] = true;    }}int main() {    ios_base::sync_with_stdio(0);    while(scanf("%d", &n) == 1) {        for(int i = 1; i <= n; ++i)            scanf("%d%d%d%d", bx + i, by + i, ux + i, uy + i);        vector<int> bad(n + 1, false);        solve(bad, bx, ux, by, uy);        solve(bad, by, uy, bx, ux);        int ans = n - count(bad.begin(), bad.end(), true);        printf("%d\n", ans);    }    return 0;}

数学

FFT

HDU 5730 Shell Necklace(dp、cdq分治+FFT)

N105iNai
b1,b2,,bmmi=1abi

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 313;const double PI = acos(-1);int n, a[N];int f[N];typedef complex<double> Complex;void rader(Complex* y, int len) {    for(int i = 1, j = len / 2; i < len - 1; i++) {        if(i < j) swap(y[i], y[j]);        int k = len / 2;        while(j >= k) {j -= k; k /= 2;}        if(j < k) j += k;    }}void fft(Complex* y, int len, int op) {    rader(y, len);    for(int h = 2; h <= len; h <<= 1) {        double ang = op * 2 * PI / h;        Complex wn(cos(ang), sin(ang));        for(int j = 0; j < len; j += h) {            Complex w(1, 0);            for(int k = j; k < j + h / 2; k++) {                Complex u = y[k];                Complex t = w * y[k + h / 2];                y[k] = u + t;                y[k + h / 2] = u - t;                w = w * wn;            }        }    }    if(op == -1) for(int i = 0; i < len; i++) y[i] /= len;}Complex A[N << 1], B[N << 1];void cdq(int l, int r) {    if(l == r) return;    int mid = (l + r) >> 1;    cdq(l, mid);    int len = 1;    while(len <= r - l + 1) len <<= 1;    for(int i = 0; i < len; i++) {        A[i] = Complex(l + i <= mid ? f[l + i] : 0, 0);        B[i] = Complex(l + i + 1 <= r ? a[i + 1] : 0, 0);    }    fft(A, len, 1);    fft(B, len, 1);    for(int i = 0; i < len; i++) A[i] *= B[i];    fft(A, len, -1);    for(int i = mid + 1; i <= r; i++) {        f[i] += fmod(A[i - l - 1].real(), MOD) + 0.5;        if(f[i] >= MOD) f[i] -= MOD;    }    cdq(mid + 1, r);}int main() {    ios_base::sync_with_stdio(0);    while(scanf("%d", &n) == 1 && n) {        for(int i = 1; i <= n; ++i) {            scanf("%d", a + i);            a[i] %= MOD;        }        memset(f, 0, sizeof f);        f[0] = 1;        cdq(0, n);        printf("%d\n", f[n]);    }    return 0;}

NTT

HDU 5829 Rikka with Subset (NTT)

N1051KNU
SUval(S):=Smin(K,|S|)
val(U)k=SUval(S)
val(U)k

/*//ntt(A, len, 1);//ntt(B, len, 1);//for(int i = 0; i < len; ++i) A[i] = A[i] * B[i] % P;//ntt(A, len, -1);//(r ^{2k}) + 1     rr  kk  gg3   1   1   25   1   2   217  1   4   397  3   5   5193 3   6   5257 1   8   37681    15  9   1712289   3   12  1140961   5   13  365537   1   16  3786433  3   18  105767169 11  19  37340033 7   20  323068673    11  21  3104857601   25  22  3167772161   5   25  3469762049   7   26  31004535809  479 21  32013265921  15  27  312281701377  17  27  33221225473  3   30  575161927681 35  31  377309411329 9   33  7206158430209    3   36  222061584302081   15  37  72748779069441   5   39  36597069766657   3   41  539582418599937  9   42  579164837199873  9   43  5263882790666241 15  44  71231453023109121    35  45  31337006139375617    19  46  33799912185593857    27  47  54222124650659841    15  48  197881299347898369    7   50  631525197391593473   7   52  3180143985094819841  5   55  61945555039024054273 27  56  54179340454199820289    29   57  3*/const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;const int G = 3, P = 998244353;LL quick(LL x, LL n) {    LL ret = 1;    for(; n; n >>= 1) {        if(n & 1) ret = ret * x % P;        x = x * x % P;    }    return ret;}LL A[N << 2], B[N << 2];void rader(LL* y, int len) {    for(int i = 1, j = len / 2; i < len - 1; i++) {        if(i < j) swap(y[i], y[j]);        int k = len / 2;        while(j >= k) {j -= k; k /= 2;}        if(j < k) j += k;    }}void ntt(LL* y, int len, int op) {    rader(y, len);    for(int h = 2; h <= len; h <<= 1) {        LL wn = quick(G, (P - 1) / h);        if(op == -1) wn = quick(wn, P - 2);        for(int j = 0; j < len; j += h) {            LL w = 1;            for(int k = j; k < j + h / 2; k++) {                LL u = y[k];                LL t = w * y[k + h / 2] % P;                y[k] = (u + t) % P;                y[k + h / 2] = (u - t + P) % P;                w = w * wn % P;            }        }    }    if(op == -1) {        LL inv = quick(len, P - 2);        for(int i = 0; i < len; i++) y[i] = y[i] * inv % P;    }}int n, a[N], f[N];LL fact[N], invf[N], two[N], invt[N];int main() {    ios_base::sync_with_stdio(0);    fact[0] = two[0] = invf[0] = invt[0] = 1;    for(int i = 1; i < N; ++i) {        fact[i] = fact[i - 1] * i % P;        two[i] = two[i - 1] * 2 % P;        invf[i] = quick(fact[i], P - 2);        invt[i] = quick(two[i], P - 2);    }    int t; scanf("%d", &t);    while(t--) {        scanf("%d", &n);        for(int i = 1; i <= n; ++i) scanf("%d", a + i);        sort(a + 1, a + n + 1, greater<int>());        int len = 1;        while(len <= n << 1) len <<= 1;        for(int i = 0; i < len; ++i) {            A[i] = i <= n ? two[n - i] * invf[i] % P : 0;            B[i] = i >= 1 && i <= n ? a[i] * fact[i - 1] % P : 0;        }        reverse(B + 1, B + n + 1);        ntt(A, len, 1);        ntt(B, len, 1);        for(int i = 0; i < len; ++i) A[i] = A[i] * B[i] % P;        ntt(A, len, -1);        for(int i = 1; i <= n; ++i) f[i] = invt[i] * invf[i - 1] % P * A[n - i + 1] % P;        for(int i = 1; i <= n; ++i) if((f[i] += f[i - 1]) >= P) f[i] -= P;        for(int i = 1; i <= n; ++i) printf("%d ", f[i]);        puts("");    }    return 0;}

FWT

IForg 1028 Bob and Alice are playing numbers

n2
106cnt[i]:=i

const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;LL quick(LL x, LL n) {    LL ret = 1;    for(; n; n >>= 1) {        if(n & 1) ret = ret * x % MOD;        x = x * x % MOD;    }    return ret;}const LL invTwo = quick(2, MOD - 2);void fwtXor(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    fwtXor(a, h);    fwtXor(a + h, h);    for(int i = 0; i < h; ++i) {        LL x1 = a[i];        LL x2 = a[i + h];        a[i] = (x1 + x2) % MOD;        a[i + h] = (x1 - x2 + MOD) % MOD;    }}void ifwtXor(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    for(int i = 0; i < h; ++i) {        // y1=x1+x2        // y2=x1-x2        LL y1 = a[i];        LL y2 = a[i + h];        a[i] = (y1 + y2) * invTwo % MOD;        a[i + h] = (y1 - y2 + MOD) * invTwo % MOD;    }    ifwtXor(a, h);    ifwtXor(a + h, h);}void fwtAnd(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    fwtAnd(a, h);    fwtAnd(a + h, h);    for(int i = 0; i < h; ++i) {        LL x1 = a[i];        LL x2 = a[i + h];        a[i] = (x1 + x2) % MOD;        a[i + h] = x2;    }}void ifwtAnd(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    for(int i = 0; i < h; ++i) {        // y1=x1+x2        // y2=x2        LL y1 = a[i];        LL y2 = a[i + h];        a[i] = (y1 - y2 + MOD) % MOD;        a[i + h] = y2;    }    ifwtAnd(a, h);    ifwtAnd(a + h, h);}void fwtOr(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    fwtOr(a, h);    fwtOr(a + h, h);    for(int i = 0; i < h; ++i) {        LL x1 = a[i];        LL x2 = a[i + h];        a[i] = x1;        a[i + h] = (x2 + x1) % MOD;    }}void ifwtOr(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    for(int i = 0; i < h; ++i) {        // y1=x1        // y2=x2+x1        LL y1 = a[i];        LL y2 = a[i + h];        a[i] = y1;        a[i + h] = (y2 - y1 + MOD) % MOD;    }    ifwtOr(a, h);    ifwtOr(a + h, h);}int n, op;const int C = 1 << 20;LL a[N], cnt[C + 10];int gao() {    for(int i = C; ~i; --i) if(cnt[i]) return i;    return -1;}int main() {    ios_base::sync_with_stdio(0);    int t; scanf("%d", &t);    while(t--) {        scanf("%d%d", &n, &op);        memset(cnt, 0, sizeof cnt);        for(int i = 1; i <= n; ++i) {            scanf("%lld", a + i);            ++cnt[a[i]];        }        static int kase = 0;        printf("Case #%d: ", ++kase);        if(op == 1) {            fwtAnd(cnt, C);            for(int i = 0; i < C; ++i) cnt[i] = cnt[i] * cnt[i] % MOD;            ifwtAnd(cnt, C);            for(int i = 1; i <= n; ++i) --cnt[a[i] & a[i]];            printf("%d\n", gao());        } else if(op == 2) {            fwtXor(cnt, C);            for(int i = 0; i < C; ++i) cnt[i] = cnt[i] * cnt[i] % MOD;            ifwtXor(cnt, C);            for(int i = 1; i <= n; ++i) --cnt[a[i] ^ a[i]];            printf("%d\n", gao());        } else {            fwtOr(cnt, C);            for(int i = 0; i < C; ++i) cnt[i] = cnt[i] * cnt[i] % MOD;            ifwtOr(cnt, C);            for(int i = 1; i <= n; ++i) --cnt[a[i] | a[i]];            printf("%d\n", gao());        }    }    return 0;}

SRM 518 NIM

题意:
2nimK109piL106

分析:
nimSGxorsum0
dpf[i][j]:=ij
f[1][j]f[i][j]=xy=jf[i1][x]×f[1][y]
andk

fwtXor(a, L)a[i] = a[i] ^ kifwtXor(a, L)ans = a[0]

Codeforces 449D Jzzhu and Numbers

  • 题意:
    • 给定长度为N≤106的数列,Ai≤106,选出0
const int N = 1e6 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;void fwtAnd(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    fwtAnd(a, h);    fwtAnd(a + h, h);    for(int i = 0; i < h; ++i) {        LL x1 = a[i];        LL x2 = a[i + h];        a[i] = (x1 + x2) % MOD;        a[i + h] = x2 % MOD;    }}void ifwtAnd(LL* a, int len) {    if(len == 1) return;    int h = len >> 1;    for(int i = 0; i < h; ++i) {        // y1=x1+x2        // y2=x2        LL y1 = a[i];        LL y2 = a[i + h];        a[i] = (y1 - y2 + MOD) % MOD;        a[i + h] = y2 % MOD;    }    ifwtAnd(a, h);    ifwtAnd(a + h, h);}int n;const int C = 1 << 20;LL cnt[C + 10], two[C + 10];int main() {    ios_base::sync_with_stdio(0);    two[0] = 1;    for(int i = 1; i < C; ++i) two[i] = two[i - 1] * 2 % MOD;    while(scanf("%d", &n) == 1) {        memset(cnt, 0, sizeof cnt);        for(int i = 1; i <= n; ++i) {            int x; scanf("%d", &x);            ++cnt[x];        }        fwtAnd(cnt, C);        for(int i = 0; i < C; ++i) cnt[i] = two[cnt[i]];        ifwtAnd(cnt, C);        printf("%I64d\n", cnt[0]);    }    return 0;}

其他

树Hash

HDU 5732 Subway(树哈希)

N10522
2

#pragma comment(linker, "/STACK:102400000,102400000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <ctime>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << "  "#define prln(x) cout << #x << " = " << x << endlconst int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;const LL seed[2] = {999999937, 999999929};const LL mod[2] = {1000000007, 1000000009}; //1e9+7/+9struct Hash {    LL h[2];    Hash() {}    Hash(const LL& first) {        for(int i = 0; i < 2; ++i) h[i] = first;    }    Hash operator+(const Hash& rhs) const {        Hash ret = *this;        for(int i = 0; i < 2; ++i) {            ret.h[i] = ret.h[i] * seed[i] % mod[i];            if((ret.h[i] += rhs.h[i]) >= mod[i]) ret.h[i] -= mod[i];        }        return ret;    }    bool operator<(const Hash& rhs) const {        return make_pair(h[0], h[1]) < make_pair(rhs.h[0], rhs.h[1]);    }    bool operator==(const Hash& rhs) const {        return make_pair(h[0], h[1]) == make_pair(rhs.h[0], rhs.h[1]);    }    void see() {        printf("(%llu %llu)\n", h[0], h[1]);    }};int n;vector<int> G[2][N];void getDiameter(int u, int f, int d, int idx, pair<int, int>& diameter) {    diameter = max(diameter, make_pair(d, u));    vector<int>& cur = G[idx][u];    for(auto& v : cur) {        if(v == f) continue;        getDiameter(v, u, d + 1, idx, diameter);    }}bool getPath(int u, int f, int t, int idx, vector<int>& path) {    path.push_back(u);    if(u == t) return true;    vector<int>& cur = G[idx][u];    for(auto& v : cur) {        if(v == f) continue;        if(getPath(v, u, t, idx, path)) return true;    }    path.pop_back();    return false;}vector<pair<Hash, int> > treeHash[2][N];Hash getHash(int u, int f, int idx) {    vector<int>& cur = G[idx][u];    vector<pair<Hash, int> > sons;    for(auto& v : cur) {        if(v == f) continue;        sons.push_back({getHash(v, u, idx), v});    }    Hash h(1);    sort(sons.begin(), sons.end());    for(auto& v : sons) h = h + v.first;    treeHash[idx][u].swap(sons);    return h;}map<string, int> mp[2];vector<string> names[2];int ID(string s, int idx) {    if(mp[idx].count(s)) return mp[idx][s];    names[idx].push_back(s);    mp[idx][s] = names[idx].size();    return mp[idx][s];}void init(int idx) {    mp[idx].clear(); names[idx].clear();    for(int i = 1; i <= n; ++i) G[idx][i].clear();}void OLE(string s) {    while(1)        puts(s.c_str());}void RE() {    printf("%d\n", *((int*)0));}bool match(vector<pair<Hash, int> >& cur, vector<pair<Hash, int> >& nxt,           vector<pair<int, int> >& ans) {    if(cur.size() != nxt.size()) return false;    int cnt = 0;    for(int i = 0; i < cur.size(); ++i) {        bool ok = false;        for(int j = i; j < nxt.size() && cur[i].first == nxt[j].first; ++j) {            swap(nxt[i], nxt[j]);            if(match(treeHash[0][cur[i].second], treeHash[1][nxt[i].second], ans)) {                ++cnt;                ok = true;                ans.push_back({cur[i].second, nxt[i].second});                break;            }        }        if(!ok) {            while(cnt--) ans.pop_back();            return false;        }    }    return true;}int main() {    ios_base::sync_with_stdio(0);    clock_t _ = clock();    while(scanf("%d", &n) == 1) {        for(int i = 0; i < 2; ++i) {            init(i);            for(int j = 1; j < n; ++j) {                char a[20], b[20]; scanf("%s%s", a, b);                int u = ID(a, i), v = ID(b, i);//                printf("%d->%d\n", u, v);                G[i][u].push_back(v);                G[i][v].push_back(u);            }//            puts("");        }        vector<pair<Hash, int> > hashes[2];        for(int i = 0; i < 2; ++i) {            pair<int, int> diameter = { -INF, -INF};            getDiameter(1, -1, 0, i, diameter);            int u = diameter.second;            diameter = { -INF, -INF};            getDiameter(u, -1, 0, i, diameter);            int v = diameter.second;//            printf("diameter %d -> %d\n", u, v);            vector<int> path;            getPath(u, -1, v, i, path);            int sz = path.size();            int x = path[sz >> 1], y = -1;            if(~path.size() & 1) y = path[sz / 2 - 1];            hashes[i].push_back({getHash(x, y, i), x});            if(~y) hashes[i].push_back({getHash(y, x, i), y});//            printf("start %d %d\n", x, y);            sort(hashes[i].begin(), hashes[i].end());        }        vector<pair<int, int> > ans;        if(!match(hashes[0], hashes[1], ans)) RE();//        prln(ans.size());        if(ans.size() != n) OLE("WA");        for(int i = 0; i < ans.size(); ++i) {            int u, v; tie(u, v) = ans[i];            printf("%s %s\n", names[0][u - 1].c_str(), names[1][v - 1].c_str());        }    }#ifdef LOCAL    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);#endif    return 0;}

VK Cup 2016 - Round 1 D. Bear and Polynomials(哈希)

N2×105NP(x)=Ni=0aixi
P(2)0ai使P(2)=0

/* 由于N非常大,所以直接算是不行的我们可以通过对素数取模来哈希这个结果,这个素数一定要比max{ai}大取2个素数,之后枚举每个系数,算出答案,比较是否相等即可,同时别忘记负数答案了各种取模,注意不要模出负数了时间复杂度O(n)*/const int N = 2e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, k;int a[N];typedef long long LL;LL ksm(LL x, LL n, LL MOD) {    LL ret = 1;    for(; n; n >>= 1) {        if(n & 1) ret = ret * x % MOD;        x = x * x % MOD;    }    return ret;}int main() {    ios_base::sync_with_stdio(0);    scanf("%d%d", &n, &k);    LL sum[2] = {}, mod[2] = {MOD, MOD + 2};    LL power[2] = {1, 1}, base[2] = {2, 2};    for(int i = 0; i <= n; ++i) {        scanf("%d", a + i);        for(int j = 0; j < 2; ++j) {            sum[j] = (sum[j] + a[i] * power[j] % mod[j]) % mod[j];            sum[j] = (sum[j] + mod[j]) % mod[j];            power[j] = power[j] * base[j] % mod[j];        }    }    int ans = 0;    for(int i = 0; i < 2; ++i) power[i] = 1, base[i] = ksm(2, mod[i] - 2, mod[i]);    for(int i = 0; i <= n; ++i) {        LL delta[2];        for(int j = 0; j < 2; ++j) {            delta[j] = (a[i] - sum[j] * power[j] % mod[j]) % mod[j];            delta[j] = (delta[j] + mod[j]) % mod[j];            power[j] = power[j] * base[j] % mod[j];        }        LL cof = INF;        if(delta[0] == delta[1]) cof = delta[0];        if(delta[0] - mod[0] == delta[1] - mod[1]) cof = delta[0] - mod[0];        if(abs(cof) > k || i == n && cof == 0) continue;        ++ans;    }    printf("%d\n", ans);    return 0;}

Codeforces Round 354 (Div. 2) E. The Last Fight Between Human and AI

N105P(x)=anxn+an1xn1+...+a1x+a0
2P(x)
Q(x)=xkP(x)Q(x)
2?
2

/* 假如所有系数ai都是确定的,如果P(x)能被x−k整除说明x−k是P(x)的一个因子,显然x=k是P(x)=0的一个根,k≠0那么讨论一下k=0的情况:如果a[0]=0,那么Q(x)已经整除P(x),反之则不能整除如果a[0]不确定,那么第一个填a[0]的人胜再仔细看一下k≠0的情况:如果系数全部确定的情况上面已经说了,代入x=k判断P(x)=0成立性对于不完全确定的情况,我们先看一下只有1个不确定的情况:令其他的确定系数的项的和为A,不确定的那项为aixi由P(x)=A+aixi=0得,ai=−Axi,由于ai可以是实数那么最后一步的操作者有必胜策略这样分2种情况讨论,每种情况里又有2种情况讨论这题就做完了对于如何算出P(k),实际上只有从高位到低位乘起来如果中间大于N×max{Ai}那么就无解了,然后判是不是0就好了当然对于zz选手的我,直接取很多素数对结果取模进行哈希判断也是可以哒*/const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, k;int a[N];int calc(int mod) {    int ret = 0;    for(int i = n; ~i; --i) ret = (1LL * ret * k + a[i]) % mod;    return ret;}int main() {    ios_base::sync_with_stdio(0);    clock_t _ = clock();    while(scanf("%d%d", &n, &k) == 2) {        int unknown = 0;        for(int i = 0; i <= n; ++i) {            char buf[10]; scanf("%s", buf);            a[i] = *buf == '?' ? INF : atoi(buf);            unknown += a[i] == INF;        }        int used = n + 1 - unknown;        if(k == 0) {            //a[0] is 0 will win            puts(a[0] == 0 || a[0] == INF && (used & 1) ? "Yes" : "No");        } else {            if(!unknown) {                bool ok = true;                for(int i = 2e9; ; ++i) {                    if(calc(i)) {ok = false; break;}                    if(1.0 * (clock() - _) / CLOCKS_PER_SEC > 0.95) break;                }                puts(ok ? "Yes" : "No");            } else puts(~(n + 1) & 1 ? "Yes" : "No");        }    }#ifdef LOCAL    printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);#endif    return 0;}

生成树计数

3ABGABaAGbBGc
AA109+7

/*叉姐给出1个有向图欧拉回路计数的定理有向图欧拉回路的话,判定条件:连通,每个点入度=出度有向图欧拉回路计数(BSET Theorem):ec(G)=ts(G)⋅deg(s)!⋅∏v∈V, v≠s(deg(v)−1)!, ts(G):=以s为根的外向树的个数注意特判1个点答案是1生成树计数(Kirchhoff Theorem):基尔霍夫矩阵K=度数矩阵D−邻接矩阵A重边:按照边数计算,自环:不计入度数无向图生成树计数:c=|K的任意1个n−1阶主子式|有向图外向树计数:c=|去掉根所在的那阶得到的主子式|以上是学习内容,这个题只要枚举一条边的其中1个方向的边数然后根据欧拉回路判定性条件解出其他边的2个方向的边数然后直接套定理解出个数,注意选边的时候要乘组合数然后这个题就做完了,时间复杂度O(n)*/const int N = 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;typedef long long LL;LL a[N][N], ans[N];bool isFreeX[N];LL gauss(int n, int m) {    for(int i = 0; i < m; ++i) isFreeX[i] = false;    LL ret = 1, neg = 0;    int r = 1, c = 1;    for(; r < n && c < m; ++r, ++c) {        int p = r;        for(; p < n; ++p) if(a[p][c]) break;        if(p == n) {--r; isFreeX[c] = true; continue;}        if(p != r) {            neg ^= 1;            for(int i = c; i <= m; ++i) swap(a[p][i], a[r][i]);        }        //eliminate coefficient        for(int i = r + 1; i < n; ++i) {            while(a[i][c]) {                LL delta = a[i][c] / a[r][c];                for(int j = c; j <= m; ++j) {                    a[i][j] += MOD - delta * a[r][j] % MOD;                    a[i][j] %= MOD;                }                if(!a[i][c]) break;                neg ^= 1;                for(int j = c; j <= m; ++j) swap(a[r][j], a[i][j]);            }        }    }    if(r != n) return 0;    for(int i = 1; i < r; ++i) ret = ret * a[i][i] % MOD;    if(neg) ret = (-ret + MOD) % MOD;    return ret;}int A, B, C;int deg[N];bool check(int& x, int A) {    if(x & 1) return false;    x /= 2;    return x >= 0 && x <= A;}const int M = 1e5 + 10;LL fact[M], finv[M];LL quick(LL x, LL n) {    LL ret = 1;    for(; n; n >>= 1) {        if(n & 1) ret = ret * x % MOD;        x = x * x % MOD;    }    return ret;}LL comb(int n, int m) {    if(n < m) return 0;    return fact[n] * finv[m] % MOD * finv[n - m] % MOD;}int main() {    ios_base::sync_with_stdio(0);    fact[0] = finv[0] = 1;    for(int i = 1; i < M; ++i) {        fact[i] = fact[i - 1] * i % MOD;        finv[i] = quick(fact[i], MOD - 2);    }    while(scanf("%d%d%d", &A, &B, &C) == 3) {        LL ans = 0;        for(int x = 0; x <= A; ++x) { //x in-degrees from A; y from C, z from B            int y = 2 * x + C - A;            if(!check(y, C)) continue;            int z = 2 * y + B - C;            if(!check(z, B)) continue;            if(x + B - z != A - x + z) continue; //check A            deg[0] = x + B - z;            deg[1] = y + A - x;            deg[2] = z + C - y;            for(int i = 0; i < 3; ++i) a[i][i] = deg[i];            a[0][1] = -(A - x); a[0][2] = -z;            a[1][0] = -x;  a[1][2] = -(C - y);            a[2][0] = -(B - z); a[2][1] = -y;            LL cur = comb(A, x) * comb(C, y) % MOD * comb(B, z) % MOD;            //BEST Theorem            cur = cur * gauss(3, 3) % MOD;            cur = cur * deg[0] % MOD;            for(int i = 0; i < 3; ++i) cur = cur * fact[deg[i] - 1] % MOD;            ans = (ans + cur) % MOD;        }        printf("%lld\n", ans);    }    return 0;}
0 0