[USACO5.5]贰五语言Two Five

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;
}

原文地址:https://www.cnblogs.com/Troverld/p/14597620.html