【USACO14FEB】洛谷3102 Secret Code

题目描述

Farmer John has secret message that he wants to hide from his cows;
the message is a string of length at least 2 containing only the
characters A..Z.

To encrypt his message, FJ applies a sequence of “operations” to it,
where an operation applied to a string S first shortens S by removing
either some (but not all) of the initial characters or some (but not
all) of the final characters from S, after which the original string S
is attached either at the beginning or end. For example, a single
operation to the string ABC could result in eight possible strings:

AABC ABABC BCABC CABC ABCA ABCAB ABCBC ABCC Given the final encrypted
string, please count the number of possible ways FJ could have
produced this string using one or more repeated operations applied to
some source string. Operations are treated as being distinct even if
they give the same encryption of FJ’s message. For example, there are
four distinct separate ways to obtain AAA from AA.

Print your answer out modulo 2014.

农民约翰收到一条的消息,记该消息为长度至少为2,只由大写字母组成的字符串S,他通过一系列操作对S进行加密。

他的操作为,删除S的前面或者后面的若干个字符(但不删光整个S),并将剩下的部分连接到原字符串S的前面或者后面。如对于S=‘ABC’,共有8总可能的操作结果:

AABC

ABABC

BCABC

CABC

ABCA

ABCAB

ABCBC

ABCC

给出加密后的目标字符串,请计算共有多少种加密的方案。

对于同字符的字符串,加密方案不止一种,比如把AA加密成AAA,共有4种加密方案。将你的答案mod 2014后输出。 输入输出格式 输入格式:

Line 1: A single encrypted string of length at most 100.

输出格式:

Line 1: The number of ways FJ could have produced this string with one or more successive operations applied to some initial string of

length at least 2, written out modulo 2014. If there are no such ways,
output zero.

先O(n^3)预处理出任意两段字串是否相等,然后进行区间dp。
具体做法是选定当前区间的一段前缀或者后缀,验证它是否是剩下一段的前缀或者后缀,如果是的话累加进那剩下一段的方案数。

#include<cstdio>
#include<cstring>
const int mod=2014;
char s[110];
int f[110][110][110],dp[110][110];
int main()
{
    int i,j,k,l,p,q,x,y,z,ans=1;
    scanf("%s",s+1);
    l=strlen(s+1);
    for (i=1;i<=l;i++)
      for (j=1;j<=l;j++)
        for (k=1;i+k-1<=l&&j+k-1<=l&&s[i+k-1]==s[j+k-1];k++)
          f[i][j][k]=1;
    for (i=1;i<=l;i++)
      for (j=i;j<=l;j++)
        dp[i][j]=1;
    for (k=2;k<=l;k++)
      for (i=1;(j=i+k-1)<=l;i++)
        for (x=1;x*2<k;x++)
        {
            if (f[i][i+x][x]) dp[i][j]=(dp[i][j]+dp[i+x][j])%mod;
            if (f[i][j-x+1][x]) dp[i][j]=(dp[i][j]+dp[i+x][j])%mod;
            if (f[i][j-x+1][x]) dp[i][j]=(dp[i][j]+dp[i][j-x])%mod;
            if (f[j-2*x+1][j-x+1][x]) dp[i][j]=(dp[i][j]+dp[i][j-x])%mod;
        }
    printf("%d\n",dp[1][l]-1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值