zoukankan      html  css  js  c++  java
  • 【NOIP模拟】奇怪的字符串

    题面

    考虑字符串 s 仅由小写字母组成,例如 "abba"。定义 W(s) 为 s 所有本质不同的连续子串的集合,例如 W("abba") = { "a","b","ab","ba","bb","abb","bba","abba" }。

    定义 Y(s) 为 s 所有本质不同的非连续子串的集合,例如 Y("abba") = W("abba") ∪ { "aa","aba" },显然 W(s)是 Y(s) 的子集。

    对于一些奇怪的字符串 s 满足 W(s) = Y(s),例如 "abba" 就不是奇怪的,但 "abb" 是奇怪的。因为 W(s) = Y(s) = { "a","b","ab","bb","abb" }。现在小明有一个字符串 s,请你求出 W(s)中有多少个字符串是奇怪的?

    注意:集合中的所有元素互不相同

    分析

    显然奇怪的只有两种,要么是aabb型要么是aaaa型,即不能由超过三部分组成。

    对于aaaa型很简单,只需要统计连续的相同字母的数量的最长是多少。

    对于aabb型,会有很多重复的情况,怎么计算呢?

    考虑这两个 aaabb和aabbb,如果按2*3和3*2分别算,显然中间有重复计算,算了aaabb的2*3后,第二个具有的贡献仅有abbb和aabbb,即(3-2)*2

    这是不是很像一个区间覆盖问题?我们把一个aabb型的写成(l,r)的点对形式,上面这两个分别是(3,2)和(2,3)

    我们对于相同的两个字母(上面是a,b),把他们按l从小到大排序,如果r超过了之前最大的r,则会产生l*(r-maxr ) 的贡献,就像上面的2*(3-2)一样

    对于aab这种,显然已经被完全覆盖了,又因为它的r并没有超过maxr,所以它也自然不会被计算。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define N 200020
    int n,ans;
    int len[30];
    char s[N];
    struct email{int l,r;};
    vector<email>v[30][30];
    bool cmp(email a,email b){return a.l>b.l;}
    void pre()
    {
        int i=1,j,l=1,r;char ml=s[1],mr;
        while(s[i]==s[i+1])i++,l++;
        while(i<n)
        {
            j=i+1;mr=s[j];r=1;
            while(j<n&&s[j]==s[j+1])j++,r++;
            v[ml-'a'][mr-'a'].push_back((email){l,r});
            i=j,l=r,ml=mr;
        }
    }
    
    inline void cal(int x,int y)
    {
        sort(v[x][y].begin(),v[x][y].end(),cmp);
        int i=0;email p=v[x][y][i];
        int ml=p.l,mr=p.r;ans+=ml*mr;i++;
        for(;i<v[x][y].size();i++)
        {
            email p=v[x][y][i];
            if(mr<p.r)ans+=p.l*(p.r-mr),mr=p.r;
        }
    
    }
    
    int main()
    {
        scanf("%s",s+1);n=strlen(s+1);
        for(int i=1;i<=n;)
        {
            int j=i;
            while(j<n&&s[j]==s[j+1])j++;
            len[s[i]-'a']=max(len[s[i]-'a'],j-i+1);
            i=j+1;
        }
        for(int i=0;i<26;i++)ans+=len[i];
        pre();
        for(int i=0;i<26;i++)
            for(int j=0;j<26;j++)
                if(v[i][j].size())
                    cal(i,j);
        printf("%d
    ",ans);
        return 0;
    }
  • 相关阅读:
    Hadoop编译源码
    大数据生态体系
    crontab任务调度
    yum概述配置
    如何识别图像边缘
    神经网络入门
    Linux命令locate
    B1299 [LLH邀请赛]巧克力棒 博弈论
    B1090 [SCOI2003]字符串折叠 区间dp
    B1068 [SCOI2007]压缩 区间dp
  • 原文地址:https://www.cnblogs.com/NSD-email0820/p/9891309.html
Copyright © 2011-2022 走看看