• LOJ#2083. 「NOI2016」优秀的拆分


    $n leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种。$t leq 10$组询问。

    $n^3$过80,$n^2$过95,鬼去写正解。。

    $n^2$:先枚举一次算每个位置结尾的AA形式的子串,再枚举一次用类似的方法算答案。

    正解:类似,记每个位置结尾的AA的子串和每个位置开头的即可。算这个数组可用如此方法:枚举A长度$L$,每A个位置标记一个关键点。然后相邻两个关键点$a,b$,找前缀$a,b$的最长公共后缀$p$和后缀$a,b$的最长公共前缀$s$,若$p+s>L$说明这里有一些A,其中作为起点的范围是$[a-p+1,a+s-L]$,作为终点的范围$[b-p+L,b+s-1]$,相当于做了个区间加,可以差分。这样做的话,复杂度就变成$frac{n}{1}+frac{n}{2}+...=n ln n$了。

    找最长公共前后缀,sa或二分hash或sam均可。

      1 //#include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 //#include<math.h>
      5 //#include<set>
      6 //#include<queue>
      7 //#include<bitset>
      8 //#include<vector>
      9 #include<algorithm>
     10 #include<stdlib.h>
     11 using namespace std;
     12 
     13 #define LL long long
     14 int qread()
     15 {
     16     char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1);
     17     do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f;
     18 }
     19 
     20 //Pay attention to '-' , LL and double of qread!!!!
     21 
     22 int T,n;
     23 #define maxn 60011
     24 char s[maxn]; int f[maxn],g[maxn];
     25 
     26 struct SAM
     27 {
     28     struct Node{int pre,ch[26],pos,Max;}a[maxn];
     29     int size,last;
     30     void clear()
     31     {
     32         size=last=0; a[0].pre=-1; a[0].pos=a[0].Max=0; memset(a[0].ch,0,sizeof(a[0].ch));
     33         le=2; memset(first,0,sizeof(first));
     34     }
     35     int pp[maxn];
     36     void insert(int c,int p)
     37     {
     38         int x=++size,y=last; memset(a[x].ch,0,sizeof(a[x].ch));
     39         a[x].Max=a[last].Max+1; a[x].pos=p; pp[p]=x;
     40         last=x;
     41         for (;~y && !a[y].ch[c];y=a[y].pre) a[y].ch[c]=x;
     42         if (!~y) a[x].pre=0;
     43         else if (a[a[y].ch[c]].Max==a[y].Max+1) a[x].pre=a[y].ch[c];
     44         else
     45         {
     46             int z=a[y].ch[c],w=++size; a[w]=a[z]; a[w].pos=p; a[w].Max=a[y].Max+1;
     47             a[z].pre=a[x].pre=w;
     48             for (;~y && a[y].ch[c]==z;y=a[y].pre) a[y].ch[c]=w;
     49         }
     50     }
     51     struct Edge{int to,next;}edge[maxn<<1]; int first[maxn],le;
     52     void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
     53     int Log[maxn<<1],rmq[22][maxn<<1],dep[maxn],Time,id[maxn];
     54     void predfs(int x)
     55     {
     56         rmq[0][++Time]=x; id[x]=Time;
     57         for (int i=first[x];i;i=edge[i].next)
     58         {
     59             Edge &e=edge[i]; dep[e.to]=dep[x]+1;
     60             predfs(e.to); rmq[0][++Time]=x;
     61         }
     62     }
     63     void pre()
     64     {
     65         for (int i=1;i<=size;i++) in(a[i].pre,i);
     66         Time=0; predfs(0);
     67         Log[0]=-1; for (int i=1,to=size*2-1;i<=to;i++) Log[i]=Log[i>>1]+1;
     68         for (int j=1;j<=18;j++)
     69             for (int i=1,to=size*2-(1<<j);i<=to;i++)
     70                 rmq[j][i]=dep[rmq[j-1][i]]>dep[rmq[j-1][i+(1<<(j-1))]]?rmq[j-1][i+(1<<(j-1))]:rmq[j-1][i];
     71     }
     72     int qq(int x,int y)
     73     {
     74         x=id[pp[x]]; y=id[pp[y]]; if (x>y) x^=y^=x^=y; int l=Log[y-x+1];
     75         return a[dep[rmq[l][x]]>dep[rmq[l][y-(1<<l)+1]]?rmq[l][y-(1<<l)+1]:rmq[l][x]].Max;
     76     }
     77 }s1,s2;
     78 //1 shi zheng de , 2 shi fan de
     79 
     80 int main()
     81 {
     82     T=qread();
     83     while (T--)
     84     {
     85         scanf("%s",s+1); n=strlen(s+1);
     86         s1.clear(); s2.clear();
     87         for (int i=1;i<=n;i++) s1.insert(s[i]-'a',i);
     88         for (int i=n;i;i--) s2.insert(s[i]-'a',i);
     89         s1.pre(); s2.pre();
     90         
     91         memset(f,0,sizeof(f));
     92         memset(g,0,sizeof(g));
     93         for (int i=1;i<=n;i++)
     94             for (int j=i;j<=n-i;j+=i)
     95             {
     96                 int k=j+i,p=s1.qq(j,k),s=s2.qq(j,k); p=min(p,i); s=min(s,i);
     97                 if (p+s>i) f[j-p+1]++,f[j+s-i+1]--,g[k-p+i]++,g[k+s]--;
     98             }
     99         
    100         for (int i=1,now=0;i<=n;i++) now+=f[i],f[i]=now;
    101         for (int i=1,now=0;i<=n;i++) now+=g[i],g[i]=now;
    102         LL ans=0;
    103         for (int i=1;i<n;i++) ans+=g[i]*1ll*f[i+1];
    104         printf("%lld
    ",ans);
    105     }
    106     return 0;
    107 }
    View Code
  • 相关阅读:
    6.简易计算器
    5.用户密码管理
    4.方法重载
    3.对象数组做参数
    2.迷你DVD管理系统
    1.二维数组计算班级成绩
    31.向数组中插入一个元素
    30.使用Arrays类的各种方法
    Java开发中的23种设计模式详解(转)
    个人代码归档
  • 原文地址:https://www.cnblogs.com/Blue233333/p/9240940.html
Copyright © 2020-2023  润新知