Topcoder 10748 - StringDecryption(dp)
神仙题。
首先这个两次加密略微有点棘手,咱们不妨先从一次加密的情况入手考虑这个问题。显然,一次加密等价于将加密过的序列划分成若干段,每一段都是 \(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)的更多相关文章
- LightOJ 1033 Generating Palindromes(dp)
LightOJ 1033 Generating Palindromes(dp) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid= ...
- lightOJ 1047 Neighbor House (DP)
lightOJ 1047 Neighbor House (DP) 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=87730# ...
- UVA11125 - Arrange Some Marbles(dp)
UVA11125 - Arrange Some Marbles(dp) option=com_onlinejudge&Itemid=8&category=24&page=sho ...
- 【POJ 3071】 Football(DP)
[POJ 3071] Football(DP) Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4350 Accepted ...
- 初探动态规划(DP)
学习qzz的命名,来写一篇关于动态规划(dp)的入门博客. 动态规划应该算是一个入门oier的坑,动态规划的抽象即神奇之处,让很多萌新 萌比. 写这篇博客的目标,就是想要用一些容易理解的方式,讲解入门 ...
- Tour(dp)
Tour(dp) 给定平面上n(n<=1000)个点的坐标(按照x递增的顺序),各点x坐标不同,且均为正整数.请设计一条路线,从最左边的点出发,走到最右边的点后再返回,要求除了最左点和最右点之外 ...
- 2017百度之星资格赛 1003:度度熊与邪恶大魔王(DP)
.navbar-nav > li.active > a { background-image: none; background-color: #058; } .navbar-invers ...
- Leetcode之动态规划(DP)专题-详解983. 最低票价(Minimum Cost For Tickets)
Leetcode之动态规划(DP)专题-983. 最低票价(Minimum Cost For Tickets) 在一个火车旅行很受欢迎的国度,你提前一年计划了一些火车旅行.在接下来的一年里,你要旅行的 ...
- 最长公共子序列长度(dp)
/// 求两个字符串的最大公共子序列长度,最长公共子序列则并不要求连续,但要求前后顺序(dp) #include <bits/stdc++.h> using namespace std; ...
随机推荐
- 【Java虚拟机6】Java内存模型(Java篇)
什么是Java内存模型 <Java虚拟机规范>中曾试图定义一种"Java内存模型"(Java Memory Model,JMM)来屏蔽各种硬件和操作系统的内存访问差异, ...
- Unity 制作不规则形状button
在游戏开发中,我们有时需要制作不规则形状的按键. Unity3d中使用UGUI的Button控件只能实现规则的长方形按钮.而通过给Button的Image组件添加对应的贴图(sprite)我们可以实现 ...
- 【二食堂】Alpha - Scrum Meeting 8
Scrum Meeting 8 例会时间:4.18 11:40 - 12:10 进度情况 组员 昨日进度 今日任务 李健 1. 实体的添加和关系的添加实现的有bug,柴博和刘阳进行了帮助issue 1 ...
- 嵌入式STM32的GPIO口工作模式的介绍
一.输入模式 1. 浮空输入 浮空输入模式下,上拉和下拉两个开关断开,高或低电平通过施密特触发器到达输入数据寄存器,CPU可以通过读取输入数据寄存器从而读取到外部输入的高低电平值. 2. 输入上拉模式 ...
- Pycharm的安装简介
Pycharm 1. Pycharm简介 PyCharm是由JetBrains打造的一款Python IDE,VS2010的重构插件Resharper就是出自JetBrains之手.同时支持Googl ...
- ELK集群之grafana(8)
Grafana的安装和读取ES数据 模拟es数据产生sjgtest.py import time import datetime from elasticsearch import Elasticse ...
- dart系列之:dart语言中的函数
目录 简介 函数的参数 main函数 匿名函数 闭包 函数的返回值 总结 简介 函数是所有编程语言都有的内容,不管是面向对象还是面向过程,函数都是非常重要的一部分.dart中的函数和java中的函数有 ...
- js 实现匀速移动
js 实现匀速移动 <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- Vue的第一课
终于学习到Vue了,美滋滋,给自己点个赞 前后端作用: 1.1vs1(一个Vue对象控制一个) <body> <div id="app"> <p> ...
- rocketmq有序消息的(四)
opic的有序消息已经成为mq的标配.而RocketMQ中是这样区分消息类型的, 普通消息也叫做无序消息,简单来说就是没有顺序的消息,而有序消息就是按照一定的先后顺序的消息类型.举个例子,produc ...