【考前模拟】加密 (正解:容斥原理或暴力)

加密
【问题描述】
有一种不讲道理的加密方法是: 在字符串的任意位置随机插入字符。 相应的,
不讲道理的解密方法就是从字符串中恰好删去随机插入的那些字符。
给定原文?和加密后的字符串?,求?有多少子串可以通过解密得到原文?。
【输入格式】
输入第一行包含一个字符串?,第二行包含一个字符串?。
【输出格式】
输出一行,包含一个整数,代表可以通过解密得到原文的?的子串的数量。
【样例输入】
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。

思路:

 

超时代码(待修改):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char T[1000010],S[210];
int kszb[1000010];
long long int J=1,ha,te,t,ans;
bool ok;
int add(int ha_now,int te_now,int ha_last)
{
    return (ha_now-ha_last-1)*(strlen(T)-(te_now))+(strlen(T)-(te_now));
}
int minuss(int length_now,int length_S){
    if(length_now==length_S)
        return -1;
    else
        return 0; 
}
int main(){
    freopen("encrypt.in","r",stdin);
    freopen("encrypt.out","w",stdout);
    cin>>T;
    cin>>S;
    kszb[0]=-1;
    for(int i=0;i<strlen(T);i++)
    {
        if(T[i]==S[0])
            kszb[J++]=i;
    }
    for(int i=1;i<J;i++)
    {
        ha=te=kszb[i],t=0,ok=0;
        while(1)
        {
            if(t==strlen(S)){
                t=0;
                te--;
                break;
            }
            if(te==strlen(T)){
                ok=1;
                break;
            }
            if(T[te]==S[t]){
                te++;
                t++;
            }
            else    te++;
        }
        if(!ok)
        {
            ans+=add(ha,te,kszb[i-1]);
            ans+=minuss(te-ha+1,strlen(S)-1);
        }
        else    break;
    }
    cout<<ans;
    fclose(stdin);
    fclose(stdout);
} 

 这是没超时的代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#ifdef WIN32
#define lll "%I64d"
#else
#define lll "%lld"
#endif
using namespace std;
char t[300010],s[210];
int l,r,lent,lens,ok;
long long ans;
int sq[300010],thead,ttail;
int front(int b,int ll,int rr)
{
    return (ll-b-1)*(lent-rr);
}
int behind(int rr)
{
    return lent-rr;
}
void pan(int ll,int rr)
{
    if((rr-ll+1)==lens) ans--;
}
void find(int &th,int &tt)
{
    int st=0;
    while(1)
    {
        if(st==lens)
        {
            tt--;
            st=0;
            break;
        }
        if(tt==lent)
        {
            ok=1;
            break;
        }
        if(t[tt]==s[st])
        {
            tt++;
            st++;
        }
        else tt++;
    }
}
int main()
{
    freopen("encrypt.in","r",stdin);
    freopen("encrypt.out","w",stdout);
    cin>>t>>s;
    lent=strlen(t);lens=strlen(s);
    for(int i=0;i<lent;i++)
     if(t[i]==s[0])
      sq[++sq[0]]=i;
    int z=sq[0];sq[0]=-1;
    for(int i=1;i<=z;i++)
    {
        ok=0;
        thead=sq[i];ttail=sq[i];
        find(thead,ttail);
        if(!ok)
        {
          ans=ans+1ll*front(sq[i-1],thead,ttail);
          ans=ans+1ll*behind(ttail);
          pan(thead,ttail);
        }
        else break;
    } 
    printf(lll,ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}

请各位同志找找不同;

posted @ 2016-11-12 16:22  一蓑烟雨任生平  阅读(141)  评论(0编辑  收藏  举报