LXX.[USACO5.5]贰五语言Two Five
这题已经在我的收藏夹里面吃了大半年的灰了
发现当表格填到某个地方后,它一定是呈现出一条逐行递减的轮廓线的。
因此,我们设\(f[a][b][c][d][e]\)表示第\(1\)行填了\(a\)个……第\(5\)行填了\(e\)个的方案数。
则只有\(5\geq a\geq b\geq c\geq d\geq e\geq 0\)的状态才是合法的。
用记忆化搜索实现。之后对于每一位确定应该填什么即可。复杂度\(25^7\)(上界,真实复杂度远远不到)
代码:
#include<bits/stdc++.h>
using namespace std;
int f[6][6][6][6][6],n;
char tp[2],s[100],t[100];
bool che(char x,int y){
return (!x)||x=='A'+y;
}
int dfs(int a,int b,int c,int d,int e){
if(a+b+c+d+e==25)return 1;
int &ret=f[a][b][c][d][e];
if(ret)return ret;
if(a<5&&che(s[a],a+b+c+d+e))ret+=dfs(a+1,b,c,d,e);
if(b<a&&che(s[b+5],a+b+c+d+e))ret+=dfs(a,b+1,c,d,e);
if(c<b&&che(s[c+10],a+b+c+d+e))ret+=dfs(a,b,c+1,d,e);
if(d<c&&che(s[d+15],a+b+c+d+e))ret+=dfs(a,b,c,d+1,e);
if(e<d&&che(s[e+20],a+b+c+d+e))ret+=dfs(a,b,c,d,e+1);
// printf("%d %d %d %d %d:%d\n",a,b,c,d,e,res);
return ret;
}
bool used[100];
int main(){
scanf("%s",tp);
if(tp[0]=='N'){
scanf("%d",&n);
int sum=0;
for(int i=0;i<25;i++)for(s[i]='A';s[i]<='Z';s[i]++){
if(used[s[i]])continue;
used[s[i]]=true;
memset(f,0,sizeof(f));
int tmp=dfs(0,0,0,0,0);
if(sum+tmp>=n)break;
sum+=tmp;
used[s[i]]=false;
}
printf("%s\n",s);
}else{
scanf("%s",t);
int res=0;
for(int i=0;i<25;i++)for(s[i]='A';s[i]<t[i];s[i]++){
memset(f,0,sizeof(f));
res+=dfs(0,0,0,0,0);
}
printf("%d\n",res+1);
}
return 0;
}