• 加密


    【问题描述】
    有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,
    不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。
    给定原文?和加密后的字符串?,求?有多少子串可以通过解密得到原文?。
    【输入格式】
    输入第一行包含一个字符串?,第二行包含一个字符串?。
    【输出格式】
    输出一行,包含一个整数,代表可以通过解密得到原文的?的子串的数量。
    【样例输入】
    abcabcabc
    cba
    【样例输出】
    9
    【样例解释】
    用[?,?]表示子串开头结尾的下标(从 0 开始编号) ,这 9 种方案是:
    [0,6],[0,7],[0,8],[1,6],[1,7],[1,8],[2,6],[2,7],[2,8]
    【数据规模和约定】
    30%的数据,|?| 1000。
    对于100%的数据,1 ≤ |?| ≤ 300,000,1 ≤ ? ≤ 200。

    /*
      这道题想出了怎么做,然而写挂了~
      预处理出t数组中每个元素对应的与它邻近的a-z分别在哪儿,然后直接模拟可做。
      一开始我预处理的与它邻近的并且与它相同的元素距离是0,所以后来模拟的时候碰到s数组类似于“abbc”这种有连续相同字符的就挂了。
      本来自己造了几组数据,和暴力的结果都一样,然而没有造到这种数据,以后对拍一定要写对拍程序!!!
    */
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define M 300010
    #define N 1010
    #define lon long long
    using namespace std;
    char t[M],s[N];
    int near[M][30],m,n,head[M],tail[M],num;
    void work(){
        int p=-1;lon tot=0;
        for(int i=0;i<m;i++){
            if(t[i]!=s[0])continue;
            tot+=(lon)(i-p)*(lon)(m-i);
            p=i;
        }
        cout<<tot;
    }
    int main(){
        freopen("encrypt.in","r",stdin);
        freopen("encrypt.out","w",stdout);
        cin>>t>>s;
        m=strlen(t);n=strlen(s);
        if(n==1){
            work();return 0;
        }
        for(int i=1;i<=26;i++) near[m][i]=M;
        for(int i=m-1;i>=0;i--){
            for(int j=1;j<=26;j++){
                if(t[i]==j+'a'-1) near[i][j]=0;
                else if(near[i+1][j]==M) near[i][j]=M;
                else near[i][j]=near[i+1][j]+1;
            }
        }
        for(int i=0;i<=m;i++){
            for(int j=1;j<=26;j++){
                if(!near[i][j])
                    near[i][j]=near[i+1][j]+1;
            }
        }
        for(int i=0;i<m;i++){
            if(t[i]!=s[0])continue;
            int j=i,sum=1;
            while(1){
                j+=near[j][s[sum]-'a'+1];
                sum++;
                if(j>=M||sum==n)break;
            }
            if(sum==n&&j<M-10){
                head[++num]=i;tail[num]=j;
            }
        }
        lon tot=0;head[0]=-1;
        for(int i=1;i<=num;i++){
            tot+=(lon)(head[i]-head[i-1])*(lon)(m-tail[i]);
        }
        cout<<tot;
        return 0;
    }
  • 相关阅读:
    异或和之和
    Wannafly挑战赛19C:多彩的树
    HDU 6035 树形dp
    利用C++套接字发送邮件
    洛谷P3368树状模板(区间更新+单点查询+差分)
    CCF 201903-1 小中大
    关于树状数组
    CODEVS 4189 (前缀是否出现)
    关于字典树
    hdu 1022 Train Problem
  • 原文地址:https://www.cnblogs.com/harden/p/6057042.html
Copyright © 2020-2023  润新知