• 牛客网暑期ACM多校训练营(第一场)


    solve 2 (D J)

    rank 138/744   18.55%

    J题 做法:复制一份数组,拼接到原数组后面,然后求一段区间不同数字的个数。树状数组优化。

    D题 做法:暴力枚举,然后用set去重。

    I题 补题:

    题意:给你一个长度为n的字符串,问这个字符串有多少种不同构的子串。

    比如abc和acb,bac,bca,cab,cba同构。

    思路:既然要求不同构的子串个数,我们不妨把6种同构字符串拼接在一起,建立SAM,对于每种串,都连接在root上,统计不同的子串个数。

    那么,若子串里含有2种及以上的字符的时候,它有6种同构字符串,且一定都在SAM中存在,且被统计过。

    所以,这种字符串每6个,价值为1。(其余5种都是同构的,所以不计数)

    还有一种串,只由一种字符串组成,比如aaa,bbb,ccc,它们互相同构,这种只会有3种同构字符串。

    怎么计算个数呢?很简单,只需要找到在原串中,最长连续单一子串的长度是多少便可,对于所有的单一串,这一个串包含它们所有。

    所以答案就出来了。

    贴代码:

    #include <bits/stdc++.h>
    using namespace std;
     
    typedef long long ll;
    const int maxn = 3e5+10;
    char s[maxn];
    int n;
    int pa[maxn<<2],son[maxn<<2][27];
    int deep[maxn<<2],cnt,root,last;
    ll tot;
     
    inline int newnode(int _deep){
        deep[++cnt]=_deep;
        return cnt;
    }
     
    inline void sam(int alp){
        int np=newnode(deep[last]+1);
        int u=last;
        memset(son[np],0,sizeof son[np]);
        while(u && !son[u][alp])son[u][alp]=np,u=pa[u];
        if(!u)pa[np]=root;
        else{
            int v=son[u][alp];
            if(deep[v]==deep[u]+1)pa[np]=v;
            else{
                int nv=newnode(deep[u]+1);
                memcpy(son[nv],son[v],sizeof son[v]);
                pa[nv]=pa[v],pa[v]=pa[np]=nv;
                while(u&&son[u][alp]==v)son[u][alp]=nv,u=pa[u];
            }
        }
        last=np;
        tot+=deep[np]-deep[pa[np]];
    }
     
    inline void pre(){
        cnt=0;
        memset(son[1],0,sizeof son[1]);
        root=last=newnode(0);
        tot=0;
    }
     
     
     
    int main(){
        while(scanf("%d",&n)!=EOF){
            scanf("%s",s);
            pre();
            for(int i=0;i<n;i++){
                if(s[i]=='a'){
                    s[i+n]='a';s[i+2*n]='b';s[i+3*n]='b';s[i+4*n]='c';s[i+5*n]='c';
                }else if(s[i]=='b'){
                    s[i+n]='c';s[i+2*n]='a';s[i+3*n]='c';s[i+4*n]='a';s[i+5*n]='b';
                }else{
                    s[i+n]='b';s[i+2*n]='c';s[i+3*n]='a';s[i+4*n]='b';s[i+5*n]='a';
                }
            }/**得到6种同构串,拼接**/
     
            n+=5*n;
            int ct=0;
            for(int i=0;i<n;i++){
                sam(s[i]-'a');ct++;
                if(ct==n/6){
                    ct=0;
                    last=1;
                }
            }
     
            ll tot2=1;
            ll cnt2=1;
            for(int i=1;i<n/6;i++){
                if(s[i]==s[i-1]){
                    cnt2++;
                    tot2=max(tot2,cnt2);
                }else{
                    cnt2=1;
                }
            }
            //cout<<tot<<" "<<tot2<<endl;
            printf("%lld
    ",(tot+3*tot2)/6);
        }
        return 0;
    }
  • 相关阅读:
    C++ 整型长度的获取 不同的系统
    第二章习题 C++
    输入cin对象的用法
    将Mnist手写数字库转化为图片形式 和标签形式
    寻找图片中数字的轮廓并裁剪 扣取数字
    Linux中的日志功能
    Linux中的系统默认日志
    Linux中进程在前后台的切换
    Linux中的服务管理
    Linux中的流程控制语句
  • 原文地址:https://www.cnblogs.com/dowhile0/p/9344524.html
Copyright © 2020-2023  润新知