The Strongest Build解题报告

发布于 2021-09-23  646 次阅读


先放个题目链接:https://codeforces.com/contest/1574/problem/D

当时没做出来,想了一阵子百思不得其解。今天A掉了说一说我的思路

先来说一下题目大意,大体就是你在打游戏,有n种装备需要选择(n<=10),每一种装备都有c个可供选择(c<=2e5),按照战力值升序给出。但是也同时存在着m(m<=2e5)种装备组合方案被ban掉了,现在让你列出没被ban掉的装备组合中能达到最大战力和的装备组合是什么样的。

解题思路:

先去想最暴力的做法,设置n个指针分别指向每一种装备最大战力值的装备,然后dfs选择哪个装备退化(指针左移),如果当前所搜索到的装备组合没有被ban掉,那么更新答案,因为这时任何一个指针左移都会使新的组合方案弱于当前战力值,所以一旦dfs搜索到了一种没被ban掉的方案了就要停止搜索了。所以说最后所有供更新答案用的组合方案都是通过被ban掉的方案演化而来。

这正解不就来了吗,我们可以枚举每一种被ban的方案,然后再枚举选择哪一个指针左移,记录哪一种方案使得战力值之和最大。

#include <bits/stdc++.h>
using namespace std;
int item[20][250005],ansum,ans[20];
int banned[250005][20];
int main(){
	map<vector<int>,bool>c;
	int n,m;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>item[i][0];
		for(int j=1;j<=item[i][0];j++){
			cin>>item[i][j];
		}
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		vector<int>v(n);
		for(int j=0;j<n;j++) {
			cin>>v[j];
			banned[i][j+1]=v[j];
		}
		c[v]=1;
	}
	int sum=0;
	vector<int>v(n);
	for(int i=1;i<=n;i++){
		sum+=item[i][item[i][0]];
		v[i-1]=item[i][0];
	}
	if(!c[v]){
		for(int i=0;i<v.size();i++){
			cout<<v[i]<<" ";
		}
		return 0;
	}
	for(int i=1;i<=m;i++){
		sum=0;
		for(int j=1;j<=n;j++){
			sum+=item[j][banned[i][j]];
		}
		for(int j=1;j<=n;j++){
			if(banned[i][j]==1) continue;
			vector<int>ttmp(n);
			for(int k=0;k<n;k++) ttmp[k]=banned[i][k+1];
			ttmp[j-1]--;
			int tmp=sum-(item[j][banned[i][j]]-item[j][banned[i][j]-1]);
			if(tmp>ansum&&!c[ttmp]){
				ansum=tmp;
				for(int k=1;k<=n;k++) ans[k]=banned[i][k];
				ans[j]--;
			}
		}
	}
	for(int i=1;i<=n;i++) cout<<ans[i]<<" ";
	return 0;
}

回忆这理想不够理想,沿途逛世间一趟只有向上