[洛谷P2750] [USACO5.5]貳五語言Two Five
洛谷題目鏈接:[USACO5.5]貳五語言Two Five
題目描述
有一種奇怪的語言叫做“貳五語言”。它的每個單詞都由A~Y這25個字母各一個組成。但是,並不是任何一種排列都是一個合法的貳五語言單詞。貳五語言的單詞必須滿足這樣一個條件:把它的25個字母排成一個5*5的矩陣,它的每一行和每一列都必須是遞增的。比如單詞ACEPTBDHQUFJMRWGKNSXILOVY,它排成的矩陣如下所示:
A C E P T
B D H Q U
F J M R W
G K N S X
I L O V Y
因為它的每行每列都是遞增的,所以它是一個合法的單詞。而單詞YXWVUTSRQPONMLKJIHGFEDCBA則顯然不合法。 由於單詞太長存儲不便,需要給每一個單詞編一個碼。編碼方法如下:從左到右,再從上到下,可以由一個矩陣的得到一個單詞,再把單詞按照字典順序排序。比如,單詞ABCDEFGHIJKLMNOPQRSTUVWXY的編碼為1,而單詞ABCDEFGHIJKLMNOPQRSUTVWXY的編碼為2。
現在,你需要編一個程序,完成單詞與編碼間的轉換。
輸入輸出格式
輸入格式:
第一行為一個字母N或W。N表示把編碼轉換為單詞,W表示把單詞轉換為編碼。
若第一行為N,則第二行為一個整數,表示單詞的編碼。若第一行為W,則第二行為一個合法的單詞。
輸出格式:
每行一個整數或單詞。
輸入輸出樣例
輸入樣例#1:
N
2
輸出樣例#1:
ABCDEFGHIJKLMNOPQRSUTVWXY
輸入樣例#2:
W
ABCDEFGHIJKLMNOPQRSUTVWXY
輸出樣例#2:
2
說明
題目翻譯來自NOCOW。
USACO Training Section 5.5
題解: 我嘗試過爆搜,但是在我\(A\)
顯然這個狀態是非常多的,接近\(25!\),所以我們需要將其中一些狀態記憶化一下.
我們設\(f[a][b][c][d][e]\)表示第\(1\)行填入了\(a\)個數,第\(2\)行填入了\(b\)個數....的方案.因為我們在填數的時候一定是一個像這樣的形狀(轉自zyzzyzzyzzyz的圖):
要填入綠色的塊之前一定要先填入黃色的塊.
那麽我們可以計算出方案數之後,就考慮如何計算答案.我們可以通過類似倍增求\(lca\)的方式來統計答案.回憶一下倍增是如何求\(lca\)的?從大到小枚舉向上跳的距離,如果超過了就不跳.這裏也是類似的方法.
我們在求方案數的時候會用一個\(vis\)
具體細節有點講不太清,看代碼吧.
#include<bits/stdc++.h>
using namespace std;
int n, vis[30];
int f[7][7][7][7][7];
char opt, s[30];
bool ok(int x, int num){
return !vis[x] || vis[x] == num;
}
int dfs(int a, int b, int c, int d, int e, int x){
if(x == 26) return 1;
if(f[a][b][c][d][e]) return f[a][b][c][d][e];
int res = 0;
if(a <= 5 && ok(a, x)) res += dfs(a+1, b, c, d, e, x+1);
if(b < a && ok(b+5, x)) res += dfs(a, b+1, c, d, e, x+1);
if(c < b && ok(c+10, x)) res += dfs(a, b, c+1, d, e, x+1);
if(d < c && ok(d+15, x)) res += dfs(a, b, c, d+1, e, x+1);
if(e < d && ok(e+20, x)) res += dfs(a, b, c, d, e+1, x+1);
return f[a][b][c][d][e] = res;
}
int main(){
int tmp; cin >> opt;
if(opt == 'N'){
cin >> n;
for(int i = 1; i <= 25; i++){
for(vis[i] = 1; ; vis[i]++){
memset(f, 0, sizeof(f));
tmp = dfs(1, 1, 1, 1, 1, 1);
if(tmp >= n) break;
n -= tmp;
}
}
for(int i = 1; i <= 25; i++) cout << (char)(vis[i]-1+'A');
cout << endl;
}
else {
int res = 0; cin >> s+1;
for(int i = 1; i <= 25; i++)
for(vis[i] = 1; vis[i] < s[i]-'A'+1; vis[i]++){
memset(f, 0, sizeof(f));
res += dfs(1, 1, 1, 1, 1, 1);
}
cout << res+1 << endl;
}
return 0;
}
[洛谷P2750] [USACO5.5]貳五語言Two Five