题面传送门

神仙题。

首先这个两次加密略微有点棘手,咱们不妨先从一次加密的情况入手考虑这个问题。显然,一次加密等价于将加密过的序列划分成若干段,每一段都是 \(xd\) 的形式表示这一段中有 \(x\) 个字符 \(d\)。那么我们就可以设 \(dp_{i}\) 表示原字符串长度为 \(i\) 的前缀可以由多少个字符串经过一次加密得到,转移就枚举上一段结尾 \(j(j\le i-2)\) 然后转移即可,只不过 \(j\) 可以转移到 \(i\) 需要满足两个条件:一是上一段的结尾与这一段的结尾不同,即 \(s_i\ne s_j\),二是这一段不能出现前导零,即 \(s_{j+1}\ne 0\)。

接下来考虑两次加密的情况,我们还是按照一次加密的情况枚举上一段的结尾 \(j\),这样第一次解密出来就是 \(x\) 个字符 \(d\),其中 \(x\) 是 \(s[j+1...i-1]\) 连接而成的 \(i-j-1\) 位数,\(d\) 是 \(s_j\) 表示的数。以 \(x=6,d=5\) 为例,第二次解密共有以下划分方法:

  • 直接跳过这 \(x\) 位数,或者说,这次解密出来的 \(6\) 个 \(5\) 完全被划分在同一段中,并且最后一个 \(5\) 不是这一段的结尾,比方说前面有 \(3\) 个 \(3\),后面有 \(2\) 个 \(7\),那么第二次解密出来的结果如下:\(3335555557\) 个 \(7\)
  • 上一段没有剩余的字符留下来,并且这段中间被断开,那么由于划分出来相邻两段的最后一个字符不能相同,故这 \(x\) 个 \(d\) 最多被切一刀(否则假设这两个断点分别为 \(i,j\),那么显然 \(s_i,s_j\) 为这两段的结尾,而由于 \(s_i=s_j\),不符合要求)。还是以 \(x=6,d=5\),前面有 \(3\) 个 \(3\),后面有 \(2\) 个 \(7\) 的情况为例,有以下 \(5\) 种划分方法:
    • \(333|55|555577\)
    • \(333|555|55577\)
    • \(333|5555|5577\)
    • \(333|55555|577\)
    • \(333|555555|77\)
  • 上一段有剩余的字符留下来,并且这段中间被断开,照样采用上面的例子,不妨设前面三个 \(3\) 在第二、三个 \(3\) 中间切了一道,那么有以下 \(6\) 种划分方式:
    • \(33|35|5555577\)
    • \(33|355|555577\)
    • \(33|3555|55577\)
    • \(33|35555|5577\)
    • \(33|355555|577\)
    • \(33|3555555|77\)

受到这个思想的启发,我们可以设 \(dp_{i,d,k}\) 表示当前解密了原字符串的前 \(i\) 位,在第一次解密出来的字符串中进行划分,划分出来最后一段的最后一位为 \(d\),当前第一次解密出来的字符串中是否有字符还没有划分为完整的一段的情况为 \(k\) 的方案数。转移还是枚举原字符串中上一段的右端点位置为 \(j\),上一段最后一个字符 \(p\),我们假设 \(s[j+1...i-1]\) 组成的数为 \(x\),\(s_i=d\),那么可以分以下情况:

  • 第一次解密出来的 \(x\) 个 \(d\) 中间没有划分,那么显然这 \(x\) 个 \(d\) 还没有被划分为完整的一段,故 \(dp_{i,p,1}\leftarrow dp_{j,p,1},dp_{i,p,1}\leftarrow dp_{j,p,0}\),当然如果 \(d=0\) 就不能从 \(dp_{j,p,0}\) 转移,因为这样会出现 \(pppp|000...0\) 的情况,就会出现前导零了。
  • 上一段没有剩余的字符留下来,并且这段中间被断开,那么共有 \(x-1\) 种可能,其中 \(x-2\) 种有字符剩余,\(1\) 种没有字符剩余,故 \(dp_{i,d,1}\leftarrow dp_{j,p,0}·(x-2),dp_{i,d,0}\leftarrow dp_{j,p,0}\),当然如果 \(d=0\) 或 \(d=p\) 就无法转移了,因为会出现前导零或者相邻两段结尾位置相同的情况,\(x=1\) 时无法转移到 \(dp_{i,d,1}\)。
  • 上一段有剩余的字符留下来,并且这段中间被断开,那么共有 \(x\) 种可能,其中 \(x-1\) 种有字符剩余,\(1\) 种没有字符剩余,故 \(dp_{i,d,1}\leftarrow dp_{j,p,1}·(x-1),dp_{i,d,0}\leftarrow dp_{j,p,1}\),同理如果 \(d=0\) 或 \(x=1\) 也无法转移到 \(dp_{i,d,1}\),因为划分出来下一段的第一个字符为 \(0\),不合法。

最终答案即为 \(dp_{n,s_n,0}\)。

时间复杂度 \(10n^2\)

const int MAXN=500;
const int MOD=1e9+9;
int n,dp[MAXN+5][11][2],pw10[MAXN+5];
struct StringDecryption{
int decrypt(vector<string> code){
string s;
for(int i=0;i<code.size();i++) s=s+code[i];
n=s.size();s=" "+s;dp[0][10][0]=pw10[0]=1;
for(int i=1;i<=n;i++) pw10[i]=10ll*pw10[i-1]%MOD;
for(int i=1;i<=n;i++){
int sum=0,dig=s[i]-'0';
for(int j=i-2;~j;j--){
sum=(sum+1ll*pw10[i-2-j]*(s[j+1]-'0'))%MOD;
if(s[j+1]=='0'||s[j]==s[i]) continue;
// printf("%d %d %d\n",i,j,sum);
for(int k=0;k<=10;k++){
if(dig!=0) dp[i][k][1]=(dp[i][k][1]+dp[j][k][0])%MOD;
dp[i][k][1]=(dp[i][k][1]+dp[j][k][1])%MOD;
if(dig!=k){
if(dig!=0){
if(!(j==i-2&&sum==1)) dp[i][dig][1]=(dp[i][dig][1]+1ll*(sum-2+MOD)*dp[j][k][0])%MOD;
dp[i][dig][1]=(dp[i][dig][1]+1ll*(sum-1+MOD)*dp[j][k][1])%MOD;
}
dp[i][dig][0]=(dp[i][dig][0]+dp[j][k][1])%MOD;
if(dig!=0&&!(j==i-2&&sum==1)) dp[i][dig][0]=(dp[i][dig][0]+dp[j][k][0])%MOD;
}
}
}
// printf("%d %d\n",dp[i][dig][0],dp[i][dig][1]);
} return dp[n][s[n]-'0'][0];
}
};

Topcoder 10748 - StringDecryption(dp)的更多相关文章

  1. LightOJ 1033 Generating Palindromes(dp)

    LightOJ 1033  Generating Palindromes(dp) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid= ...

  2. lightOJ 1047 Neighbor House (DP)

    lightOJ 1047   Neighbor House (DP) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87730# ...

  3. UVA11125 - Arrange Some Marbles(dp)

    UVA11125 - Arrange Some Marbles(dp) option=com_onlinejudge&Itemid=8&category=24&page=sho ...

  4. 【POJ 3071】 Football(DP)

    [POJ 3071] Football(DP) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4350   Accepted ...

  5. 初探动态规划(DP)

    学习qzz的命名,来写一篇关于动态规划(dp)的入门博客. 动态规划应该算是一个入门oier的坑,动态规划的抽象即神奇之处,让很多萌新 萌比. 写这篇博客的目标,就是想要用一些容易理解的方式,讲解入门 ...

  6. Tour(dp)

    Tour(dp) 给定平面上n(n<=1000)个点的坐标(按照x递增的顺序),各点x坐标不同,且均为正整数.请设计一条路线,从最左边的点出发,走到最右边的点后再返回,要求除了最左点和最右点之外 ...

  7. 2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)

    .navbar-nav > li.active > a { background-image: none; background-color: #058; } .navbar-invers ...

  8. Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)

    Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...

  9. 最长公共子序列长度(dp)

    /// 求两个字符串的最大公共子序列长度,最长公共子序列则并不要求连续,但要求前后顺序(dp) #include <bits/stdc++.h> using namespace std; ...

随机推荐

  1. 【Java虚拟机2】Java类加载机制

    前言 JAVA代码经过编译从源码变为字节码,字节码可以被JVM解读,使得JVM屏蔽了语言级别的限制.才有了现在的kotlin.Scala.Clojure.Groovy等语言. 字节码文件中描述了类的各 ...

  2. AIApe问答机器人项目Scrum Meeting博客汇总

    荡起双桨 Scrum Meeting 博客汇总 一.Alpha阶段 AIApe问答机器人Scrum Meeting 4.23 AIApe问答机器人Scrum Meeting 4.25 AIApe问答机 ...

  3. 扩展spring data jpa的repository

    在我们编写代码的过程中,spring data jpa为我们的持久层提供的极大的方便,但有时spring data jpa提供的repository并不能完全满足我们开发的需求,因此就需要进行扩展.s ...

  4. Noip模拟37 2021.8.12

    T1 数列 真是考场上不是数学的乱推柿子,想定理,是数学的没想出来.. 比较悲伤... 列柿子不用动脑子,就是没有想出来$EXgcd$解不定方程,淦.. 解处一组解后利用比较显然的性质: $x+\fr ...

  5. 转:汇编中EBP寄存器和ESP寄存器的区别

    EBP和ESP都是汇编中关于指针的寄存器.但是定义不同: (1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶.(2 ...

  6. error: ‘int64_t’ does not name a type

    我在CodeBlock中编译工程没有出现问题,但是放到ubuntu上用自己写的Makefile make的时候报错 error: 'int64_t' does not name a type # 2 ...

  7. hdu 3038 How Many Answers Are Wrong(并查集)

    题意: N和M.有N个数. M个回答:ai, bi, si.代表:sum(ai...bi)=si.如果这个回答和之前的冲突,则这个回答是假的. 问:M个回答中有几个是错误的. 思路: 如果知道sum( ...

  8. hdu 5166 Missing number(。。。)

    题意: 有一个排列,但少了两个数.给你少了这两个数的排列.找出是哪两个数. 思路: 看代码,,, 代码: int a[1005]; int main(){ int T; cin>>T; w ...

  9. linux 内核修炼之道——系统调用

    1.问:什么是系统调用? 用户应用程序访问并使用内核所提供的各种服务的途径即是系统调用,也称系统调用接口层. 2.问:为什么需要系统调用? ① 系统调用作为内核和应用程序之间的中间层,扮演了一个桥梁角 ...

  10. Java RMI学习与解读(三)

    Java RMI学习与解读(三) 写在前面 接下来这篇就是最感兴趣的Attack RMI部分了. 前面也说过,RMI的通信过程会用到反序列化,那么针对于RMI的三个角色: Server/Regisrt ...