Codeforces A ACM (ACronym Maker) (dp)
http://codeforces.com/gym/100650
概要:给出一个缩写,和一些单词,从单词中按顺序选一些字母作为缩写,问方案数。
限制:某些单词要忽略,每个单词至少要选一个字母。
dp[i][j]表示到第i个单词的时候已经选了j个字母的方案数。
很明显,当前字符ch是第j个字符的时候,第j-1个字母只能在上一个单词或者这个单词中ch之前出现,所以有dp[i][j] += dp[i][j-1] + dp[i-1][j-1]。
边界条件为dp[i][0] = 1。由于i只由i-1和自身决定因此可用滚动数组优化。
#include<bits/stdc++.h> using namespace std; int n; const int maxn = 166; char str[maxn]; char tar[maxn]; char word[maxn]; int sscan_line(char *s,char *&s0) { if(!*s0) return 0; int i = 0, j = 0; while(s0[i] == ' ') i++; for(j = 0;s0[i] && s0[i] != ' '; i++){ s[j++] = s0[i]; } s[j] = '\0'; s0+=i; return j; } int main() { //freopen("in.txt","r",stdin); while(~scanf("%d",&n)&&n){ set<string> ig; while(n--){ scanf("%s",str); ig.insert(str); } scanf("\n"); while(gets(str) && strcmp(str,"LAST CASE") != 0){ //stringstream sin.(str) char *p = str; int tlen = sscan_line(tar,p); int dp[maxn]={} ; dp[0] = 1; for(int i = 0; tar[i]; i++){ tar[i] += 'a'-'A'; } while(sscan_line(word,p)){ if(ig.count(word) != 0) continue; int ndp[maxn]={}; for(int i = 0; word[i]; i++) for(int j = tlen-1; ~j; j--) if(word[i] == tar[j]) ndp[j+1] += dp[j]+ndp[j]; copy(ndp,ndp+maxn,dp); } for(int i = 0; i < tlen; i++){ tar[i] -= 'a'-'A'; } int ans = dp[tlen]; if(ans) printf("%s can be formed in %d ways\n",tar,ans); else printf("%s is not a valid abbreviation\n",tar); } } return 0; }