[CF377C]Captains Mode
题目
题解
刚开始我以为这是个贪心,然后打了这样一个代码
inline void Solve(){
int pts=1,ans=0;
char opt[5];int team;
while(m--){
scanf("%s %d",opt,&team);
if(opt[0]=='p')ans+=(team==1?1:-1)*val[pts];
++pts;
}writc(ans,'\n');
}
然后 \(WA\) 穿了......
显然贪心是不对的,因为如果一个人有很多个操作,他在 \(ban\) 的回合,不一定会 \(ban\) 掉战力最高的英雄
如何解决这个问题?
由于每个队长执行的操作是保证最优的,我们可以定义 dfs(now,s)
为执行到操作 \(now\),剩下的英雄状态为 \(s\) 时,当前操作的队伍能让差变得多大(返回值),那么,对于一个操作 \(i\),如果操作 \(i\) 和 \(i+1\) 是同一队执行,那么差值显然是叠加,否则,最大差值肯定是作差。
为什么这样设计?因为我们要保证每一队都进行最优选择。
在很多类似的题目中,都保证双方执行最优解时,我们都可以这样进行处理,这是一个很好的方法——线交替先后手地位,用作和或作差对解进行叠加。
对于每一个操作,我们可以暴力枚举我们应该 \(pick/ban\) 掉哪个英雄,为降低复杂度,我们可以定义 \(f[i][j]\) 为 dfs(i,j)
的返回值。
而我们有四个操作,\(pick,ban,miss\space pick,miss\space ban\),但是对于 \(pick\) 的回合,选择一定比不选择更优,对于 \(ban\),如果是 \(miss\space ban\) 也相当于 \(ban\) 掉一个最差的英雄,对结果不影响,也就是说,我们只需要考虑 \(pick\) 和 \(ban\) 两种操作即可。
对于时间复杂度的分析,因为两队都进行最优选择,那么一定不会选择差的英雄,也相当于,只有前 \(m\) 个战力最大的英雄有用,那么时间复杂度为 \(\mathcal O(20\times 20\times 2^{20})=\mathcal O(419430400)\)?(为什么还可以过)
代码
#include<cstdio>
#include<algorithm>
using namespace std;
#define rep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i<=i##_end_;++i)
#define fep(i,__l,__r) for(signed i=(__l),i##_end_=(__r);i>=i##_end_;--i)
#define erep(i,u) for(signed i=tail[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
typedef long long LL;
// typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef unsigned uint;
#define Endl putchar('\n')
// #define int long long
// #define int unsigned
// #define int unsigned long long
#define cg (c=getchar())
template<class T>inline void read(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
template<class T>inline T read(const T sample){
T x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T>void fwrit(const T x){//just short,int and long long
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);
putchar(x%10^48);
}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=100;
const int MAXM=20;
const int MAXSIZE=(1<<20);
const int INF=(1<<30)-1;
int a[MAXN+5],n,m,all;
char opt[MAXM+5][5];
int team[MAXM+5];
inline bool cmp(const int x,const int y){return x>y;}
inline void Init(){
n=read(1);
rep(i,0,n-1)a[i]=read(1);
sort(a,a+n,cmp);
n=m=read(1);
all=(1<<m)-1;
rep(i,0,m-1)scanf("%s %d",opt[i],&team[i]);
}
int f[MAXM+5][MAXSIZE+5];
bool vis[MAXM+5][MAXSIZE+5];
int Dfs(const int step,const int s){
// printf("Now step == %d, s == %d\n",step,s);
if(vis[step][s])return f[step][s];
vis[step][s]=true;
f[step][s]=-INF;
if(opt[step][0]=='p'){
rep(i,0,m-1)if((s>>i)&1){
if(step==m-1)f[step][s]=Max(f[step][s],a[i]);
else if(team[step]==team[step+1])
f[step][s]=Max(f[step][s],a[i]+Dfs(step+1,s^(1<<i)));
else f[step][s]=Max(f[step][s],a[i]-Dfs(step+1,s^(1<<i)));
}
}else{
rep(i,0,m-1)if((s>>i)&1){
if(step==m-1)f[step][s]=Max(f[step][s],0);
else if(team[step]==team[step+1])
f[step][s]=Max(f[step][s],Dfs(step+1,s^(1<<i)));
else f[step][s]=Max(f[step][s],-Dfs(step+1,s^(1<<i)));
}
}return f[step][s];
}
#define sign(x) ((x)==1?1:-1)
signed main(){
Init();
writc(sign(team[0])*Dfs(0,all),'\n');
return 0;
}