博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【Foreign】字串变化 [DP]
阅读量:5981 次
发布时间:2019-06-20

本文共 2459 字,大约阅读时间需要 8 分钟。

字串变化

Time Limit: 10 Sec  Memory Limit: 128 MB

Description

  定义一个(大写字母)字符串集合{S},初始时值包含一个给定的字符串S1,每次从中任意取出一个字符串,将它变换后再放入集合中。要求新的字符串在集合中没有出现过。

  变换的规则:在变化前、后,字符串均有大写字母组成,每次只改动一个位置,使它的ASCLL加1。例如:‘A’ –> ‘B’。如果位置为‘Z’,则无法改动。
若干次操作后,该集合的元素个数一定会达到最大。
  对最后的集合(已按字典序排列)中的Si(i >1),定义Sj=P[Si](Si由Sj变化而来)。
  求最大元素个数及{P}的方案数。(详情见样例。)

Input

  第1行有1个由大写字母组成的字符串。

Output

  输出2行,每行包含一个数,第一行表示最大元素个数,第二行表示方案数,答案都模10007。

Sample Input

  XYZ

Sample Output

  6

  4

  explain:

  最终集合为{XYZ,XZZ,YYZ,YZZ,ZYZ,ZZZ}
  {P}方案有{0,1,1,2,3,4},{0,1,1,3,3,4},{0,1,1,2,3,5},{0,1,1,3,3,5}

HINT

  初始字符串长度<=1000.

Solution

  第一问乘一下就好了,这里讨论一下第二问。

  用'Z'-ai得到一个数字串,那么操作就变成了:每次将一个数字-1,最后全部减成0。比如'XYZ',我们将其变成'012'
  然后考虑状态是怎么变来的:
  显然,有几位是不满的,就有几种转移来的方法(其中任意一位数字+1,即可得到一种父状态)。
  记一个状态可以由k个状态转移过来,然后答案显然就是:πk
  我们考虑,
  我们得到一个长度为n01串vis,如果这一位是1表示这一位不满
  那么这个01串对答案的贡献就是:k ^ (π [vis_i=1]*a_i)。(k表示1的个数
  为什么呢?对于一个位置,当这一位是[0,ai-1]都是不满的个数就是ai
  然后这样枚举每一位是否满,可以做到O(2^n)
  我们考虑优化
  把k相同的放在一起计算,记贡献为k^num[k]num[k]即是各种1的个数为k情况的指数之和
  num怎么得到呢?
  用f[i][j]表示到了第i位,有j个数不满的方案数,显然可以得到这样的递推式子:
  f[i][j] = f[i-1][j] + f[i-1][j-1] * ('Z'-a[i])
  然后Ans = π k^f[n][k],就解决了这题qwq。

Code

1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9 using namespace std; 10 typedef long long s64;11 12 const int ONE = 4005;13 const int MOD = 10007;14 15 int n;16 int a[ONE];17 char ch[ONE];18 int f[ONE][ONE];19 int Ans;20 21 int get()22 { 23 int res=1,Q=1;char c; 24 while( (c=getchar())<48 || c>57 ) 25 if(c=='-')Q=-1; 26 res=c-48; 27 while( (c=getchar())>=48 && c<=57 ) 28 res=res*10+c-48; 29 return res*Q;30 }31 32 int Quickpow(int a, int b)33 {34 int res = 1;35 while(b)36 {37 if(b & 1) res = (s64)res * a % MOD;38 a = (s64)a * a % MOD;39 b >>= 1;40 }41 return res;42 }43 44 int main()45 {46 scanf("%s", ch + 1);47 n = strlen(ch + 1);48 49 for(int i=1; i<=n; i++)50 a[i] = 'Z' - ch[i];51 52 Ans = 1;53 for(int i=1; i<=n; i++)54 Ans = (s64)Ans * (a[i]+1) % MOD;55 printf("%d\n", Ans); Ans = 1;56 57 f[0][0] = 1;58 for(int i=1; i<=n; i++)59 {60 f[i][0] = 1;61 for(int j=1; j<=i; j++)62 f[i][j] = (f[i-1][j] + f[i-1][j-1] * a[i] % (MOD - 1)) % (MOD - 1); 63 }64 65 for(int k=1; k<=n; k++)66 Ans = (s64)Ans * Quickpow(k, f[n][k]) % MOD;67 68 printf("%d", Ans);69 }
View Code

 

 

 

 

转载于:https://www.cnblogs.com/BearChild/p/7073578.html

你可能感兴趣的文章
keepalived + nginx轮询方式 做高可用和负载均衡 访问后端apache web 服务
查看>>
淘宝大秒系统设计详解
查看>>
Linux基础--系统启动流程
查看>>
Maven常用插件列表
查看>>
Successful Fashion Portfolio Photographer
查看>>
kubernetes使用Træfik代理服务
查看>>
数组更新检测
查看>>
最佳实践系列丨Docker EE 日志记录最佳实践(一)
查看>>
聊聊Web App、Hybrid App与Native App的设计差异
查看>>
RecyclerView 加载多种Item布局
查看>>
Linux基础(day8)
查看>>
开发者论坛一周精粹(第四十六期)云监控报警规则TCP连接数究竟指什么?
查看>>
java在Linux服务器上给新生成的pdf文件以及父文件夹赋予权限
查看>>
基于Netty的IM简单实现原理
查看>>
众说区块链:浅谈数字货币交易所
查看>>
进度条控件显示(C#)
查看>>
python 笔记 之 异常Exception
查看>>
如何打造7*24h持续交付通道?阿里高级技术专家的5点思考
查看>>
50 行 Python 代码,带你追到最心爱的人
查看>>
ZooKeeper应用——解决分布式系统单点故障
查看>>