 /**//*
目標串是有U個大寫字母,L個小寫字母
給出P個合法的字母對(a,b)
表示目標串相鄰的字母必滿足這些字母對,不能由其他組成
問有多少種可能的目標串
U,L <= 250
P <= 200

我比較土,總共52個字母,建立52個點的圖
狀態是(pos, u, l) 在點pos處,還剩下u個大寫,l個小寫的總數
其實O(ULP)的dp即可 (我之前也有想過的,但是轉移我居然是枚舉字母來轉移52*52,然后就放棄了)
轉移應該是枚舉字母對!!! 總共P個

*/
#include<iostream>
#include<cstring>
#include<map>
#include<algorithm>
#include<stack>
#include<queue>
#include<cmath>
#include<string>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<set>
#include<list>
#include<numeric>
#include<cassert>
#include<ctime>

using namespace std;

const int MOD = 97654321;

char validPair[201][3];
int dp[251][251][52];

 inline int get(char ch) {
return isupper(ch) ? 26+ch-'A' : ch-'a';
}

int main()
  {
#ifndef ONLINE_JUDGE
freopen("in","r",stdin);
#endif

 for(int U, L, P; ~scanf("%d%d%d", &U, &L, &P); ) {
 for(int i = 0 ; i < P ; i++) {
scanf("%s", validPair[i]);
//先get完,后面在計算時就不用再次get 快很多
validPair[i][0] = get(validPair[i][0]);
validPair[i][1] = get(validPair[i][1]);
}
memset(dp, 0, sizeof dp);
 for(int j = 0 ; j < 52 ; j++) {
dp[(j>=26)][(j<26)][j] = 1;
}
 for(int u = 0 ; u <= U ; u ++) {
 for(int l = 0; l <= L ; l++) {
 if(u+l <= 1) {
continue;
}
 for(int i = 0; i < P ; i++) {
int first = validPair[i][0];
int second = validPair[i][1];
 if(second < 26 && l > 0) {
dp[u][l][second] += dp[u][l-1][first];
dp[u][l][second] %= MOD;
}
 if(second >= 26 && u > 0) {
dp[u][l][second] += dp[u-1][l][first];
dp[u][l][second] %= MOD;
}

}
}
}
printf("%lld\n", accumulate(dp[U][L], dp[U][L]+52, 0LL) % MOD);
}
return 0;
}


|
|
常用鏈接
隨筆分類
Links
搜索
最新評論

|
|