time limit: 10 sec memory limit: 128 mb
定義乙個(大寫字母)字串集合,初始時值包含乙個給定的字串s1,每次從中任意取出乙個字串,將它變換後再放入集合中。要求新的字串在集合中沒有出現過。
變換的規則:在變化前、後,字串均有大寫字母組成,每次只改動乙個位置,使它的ascll加1。例如:『a』 –> 『b』。如果位置為『z』,則無法改動。
若干次操作後,該集合的元素個數一定會達到最大。
對最後的集合(已按字典序排列)中的si(i >1),定義sj=p[si](si由sj變化而來)。
求最大元素個數及的方案數。(詳情見樣例。)
第1行有1個由大寫字母組成的字串。
輸出2行,每行包含乙個數,第一行表示最大元素個數,第二行表示方案數,答案都模10007。
xyz6
4explain:
最終集合為
方案有,,,
初始字串長度<=1000.
第一問乘一下就好了,這裡討論一下第二問。
用'z'-ai得到乙個數字串,那麼操作就變成了:每次將乙個數字-1,最後全部減成0。比如'xyz',我們將其變成'012'。
然後考慮狀態是怎麼變來的:
顯然,有幾位是不滿的,就有幾種轉移來的方法(其中任意一位數字+1,即可得到一種父狀態)。
記乙個狀態可以由k個狀態轉移過來,然後答案顯然就是:πk。
我們考慮,
我們得到乙個長度為n的01串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。
1 #include2 #includeview code3 #include4 #include5 #include6 #include7 #include8 #include9
using
namespace
std;
10 typedef long
long
s64;
1112
const
int one = 4005;13
const
int mod = 10007;14
15int
n;16
inta[one];
17char
ch[one];
18int
f[one][one];
19int
ans;
2021
intget
()22
3132
int quickpow(int a, int
b)33
41return
res;42}
4344
intmain()
4564
65for(int k=1; k<=n; k++)
66 ans = (s64)ans * quickpow(k, f[n][k]) %mod;
6768 printf("%d"
, ans);
69 }
字串型別的變化
1.format 方法的基本使用 模板字串 format 逗號分隔的引數 模板字串有一系列槽組成,用來控制修改字串中嵌入值出現的位置,其基本思想是將format 方法中逗號分隔的引數按照序號關係替換到模板字串的槽中槽用 表示,如果大括號中沒有序號則按照出現順序替換。如果大括號中指定了使用引數的序號,...
DP 字串變換
給定兩個字串,已知可以使用三種方式進行變換 1.插入乙個字元 2.刪除乙個字元 3.更改乙個字元 請設計乙個演算法,找到兩個字串之間的經歷幾次最小變換,可以字串1轉換成字串2 輸入描述 輸入兩個字串,字串的長度 1000輸出描述 最小變換次數示例1 hello helle1 include usin...
字串dp系列
647.回文子串 給定乙個字串,你的任務是計算這個字串中有多少個回文子串。具有不同開始位置或結束位置的子串,即使是由相同的字元組成,也會被計為是不同的子串。示例 1 輸入 abc 輸出 3 解釋 三個回文子串 a b c 示例 2 輸入 aaa 輸出 6 說明 6個回文子串 a a a aa aa ...