CF377C Captains Mode

洛谷传送门 CF传送门

Solution

很显然的,两个队列肯定选择最强的,即使 \(m\) 个操作均为‘b’操作,这些操作也只和最强的 \(m\) 个英雄有关。

发现题目中 \(m\leq \min(n,20)\) ,所以可以考虑状压DP。

在DP之前,还有一点问题——跳过‘p’和'b'怎么办?

对于跳过‘p’,因为两边都是最优策略,所以自己选择一定比随机优;对于跳过‘b’,就相当于禁了最弱的那个,没有影响。

那么现在操作只有‘p’和'b',设 \(dp_{st,pos}\) 表示当前状态是 \(st\) ,现在是第 \(pos\) 个操作,(一队减二队)最大的得分。对于操作 \(i\) ,如果 \(i\)\(i-1\) 是一个队的操作,最优一定是相加;如果不是,最优一定是做差。


(关于我的博客 \(\LaTeX\) 又锅了这件事)

其中 \(op_{pos}\) 表示是哪个队操作的, \(type_{pos}\) 表示是哪种操作。

肉眼可见,这个转移方程分类讨论了许多,所以选择拿记忆化搜索来转移。( ̄▽ ̄)"

注意:因为刚开始的 \(dp_{0,m-1}\) 我们是默认 \(op_{m-1}=1\) 来做的,所以如果 \(op_{m-1}=2\) ,在求完 \(dp_{0,m-1}\) 后要取反。

Code

#include<bits/stdc++.h>

using namespace std;
const int N=1<<20,INF=0x3f3f3f3f;
int dp[N][20],n,m,a[110],type[50],op[50];
bool vis[N][20];
char s[5];

int  dfs(int st,int pos){
    if(vis[st][pos]) return dp[st][pos];
    vis[st][pos]=true;
    int & ans=dp[st][pos];
    ans=-INF;
    if(type[pos]){
        for(int i=0;i<m;i++){
            if((1<<i)&st) continue;
            if(pos==0) ans=max(ans,a[i]);
            else if(op[pos]==op[pos-1])
                      ans=max(ans,a[i]+dfs(st|(1<<i),pos-1));
                 else ans=max(ans,a[i]-dfs(st|(1<<i),pos-1));
        }
    }
    else{
        for(int i=0;i<m;i++){
            if((1<<i)&st) continue; 
            if(pos==0) ans=max(ans,0);
            else if(op[pos]==op[pos-1])
                      ans=max(ans,dfs(st|(1<<i),pos-1));
                 else ans=max(ans,-dfs(st|(1<<i),pos-1));
        }
    }
    return ans;
}

int main(){
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for(int i=m-1;i>=0;i--){
        scanf("%s%d",s,&op[i]);
        type[i]=(s[0]=='p');
    }
    sort(a,a+n);
    for(int i=0;i<m;i++)
        swap(a[i],a[n-i-1]);
    int ans=dfs(0,m-1);
    if(op[m-1]==2) ans=-ans;//取反
    printf("%d\n",ans);
    return 0;
}
posted @ 2020-11-27 19:35  jasony_sam  阅读(199)  评论(0编辑  收藏  举报