大意:给定一个字符长度及权值,让你求组成该权值的字符的全部排列,字符串严格遵循上升序列。
思路:设d[i][j][s]表示当前字符为i时,剩余长度为j,组成的权值为s的可能情况,由于遵循严格的上升序列,事实上,初始化只需写一遍即可。因为设长度为L’的集合为S‘,长度为L的集合为L,若L' < L,由于遵循该字符串严格的上升序列,则S‘<S,说明S'是S的真子集,所以可以从S'递推出S,无需再进行初始化。
记忆化搜索时,注意边界条件,每次都是在这里纠结,WA。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
int d[30][30][600];
bool vis[30][30][600];
int L, S;
int dp(int i, int j, int s)
{
int &ans = d[i][j][s];
if(j == 0) return (s == 0)? 1:0;
if(s < 0 || i > 26 || j > 26 || s > 360) return 0;
if(vis[i][j][s]) return ans;
vis[i][j][s] = 1;
ans = 0;
for(int t = i; t <= 26; t++) ans += dp(t+1, j-1, s-t);
return ans;
}
void solve()
{
int ans = dp(1, L, S);
printf("%d\n", ans);
}
int main()
{
int times = 0;
memset(vis, 0, sizeof(vis));
while(scanf("%d%d", &L, &S) && (L || S))
{
printf("Case %d: ", ++times);
solve();
}
return 0;
}