【Foreign】字串变化 [DP]

字串变化

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<iostream>
 2 #include<string>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cmath>
 8 #include<bitset>
 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 }

时间: 2024-08-28 22:16:39

【Foreign】字串变化 [DP]的相关文章

code vs1099 字串变化 字符串搜索(STL)

题目链接: http://codevs.cn/problem/1099/ 题解思路: 1.用string 类型来保存字符串 方便插入比较等操作 2.用STL set<string>来判断当前字符串是否出现过 注意字符串的下标 代码: #include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> #include<set

最长公共子序列与最长公共字串

显然最长公共子序列不一定需要连续的,只要字符的顺序严格递增即可.最长公共字串需要字符连续 子序列代码: package test; import java.util.*; /* * 本题是求最长公共子序列,子序列未必连续,只需要严格递增即可 * 如 abcdeeeeeeeee和atttbggcd 最长公共子序列为abcd 长度为4 * * */ public class Main4{ public static void main(String... args){ try(Scanner in

无重复字符的最长字串问题

leetcode3:无重复字符的最长字串问题 问题描述 给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度. 示例 1: 输入: "abcabcbb"输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3.示例 2: 输入: "bbbbb"输出: 1解释: 因为无重复字符的最长子串是 "b",所以其长度为 1.示例 3: 输入: "pwwkew"输出: 3 这道题,我自己的

【经典算法】寻找最长01字串(转自待字闺中)

这两天在微信公众号“待字闺中”中看到一个经典的面试算法,寻找最长01字串,原题目是这么说的: 给定一个数组,数组中只包含0和1.请找到一个最长的子序列,其中0和1的数量是相同的. 例1:10101010 结果就是其本身.例2:1101000 结果是110100 这个题目,看起来比较简单,一些同学可能认为题目的描述符合动态规划的特征,然后就开始用动态规划解,努力找状态转移方程.这些同学的感觉,是很正确的.但,找状态转移方程,我们要对原来的数组进行变换一下. 原来是0和1的串,我们将0都换为-1.这

洛谷P1279 字串距离

P1279 字串距离 题目描述 设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X的扩展串,这里“□”代表空格字符. 如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1与B1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其他任意字符之间的距离为已知

YJX_Driver_038_内核模式下的字串操作

1. 内核模式下的字串操作 A.ASCII字符串和UNICODE字符串 B.ANSI_STRING字符串和UNICODE_STRING字符串 C.字符串的初始化与销毁 D.字符串复制,比较,(大小写,整数和字串)相互转换 E.ANSI_STRING字符串和UNICODE_STRING字符串相互转换 2. A.ASNI字符串和UNICODE字符串 在C语言中,有ANSI和UNICODE 两个不同字串类型. char* s1="abc"; //CHAR * s1="abc&quo

(字符串)最长公共字串(Longest-Common-SubString,LCS)

题目: 给定两个字符串X,Y,求二者最长的公共子串,例如X=[aaaba],Y=[abaa].二者的最长公共子串为[aba],长度为3. 子序列是不要求连续的,字串必须是连续的. 思路: 1.简单思想: 遍历两个字符串X.Y,分别比较X的字串与Y的字串,求出最长的公共字串. #include <iostream> #include <vector> using namespace std; int getComLen(char *str1,char *str2){ int len=

华为机试-公共字串计算

题目描述题目标题:计算两个字符串的最大公共字串的长度,字符不区分大小写详细描述:接口说明原型:int getCommonStrLength(char * pFirstStr, char * pSecondStr);输入参数: char * pFirstStr //第一个字符串 char * pSecondStr//第二个字符串 输入描述:输入两个字符串 输出描述:输出一个整数 输入例子:asdfas werasdfaswer 输出例子:6 效率低的Java程序实现: import java.ut

1501110919-蓝桥杯-算法训练 字串统计

算法训练 字串统计 时间限制:1.0s   内存限制:512.0MB 问题描述 给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),如果有多个,输出最长的,如果仍然有多个,输出第一次出现最早的. 输入格式 第一行一个数字L. 第二行是字符串S. L大于0,且不超过S的长度. 输出格式 一行,题目要求的字符串. 输入样例1: 4 bbaabbaaaaa 输出样例1: bbaa 输入样例2: 2 bbaabbaaaaa 输出样例2: aa 数据规