P10192 [USACO24FEB] Moorbles S 题解

银组只会这题qwq


考虑将奇数和偶数分开计算。如果 Elsie 在回合 \(i\) 猜奇数,那么对 Elise 的最坏可能是:

  1. 存在偶数

Bessie 把 \(a_{i,1},a_{i,2},\dots,a_{i,K}\)最大的偶数放在蹄子下。Elsie 的弹珠数量减去该数。

  1. 不存在偶数

Bessie 把 \(a_{i,1},a_{i,2},\dots,a_{i,K}\)最小的奇数放在蹄子下。Elsie 的弹珠数量加上该数。

猜偶数同理。


考虑倒过来想。如果要 Elsie 不输,那么游戏结束后(“第 \(m+1\) 回合”)她至少要有 \(1\) 个弹珠,且在游戏过程中没有出现少过 \(1\) 个弹珠的回合。

考虑 DP。

状态表示:

\(\text{exist}[x][0/1]\) = Bessie 在第 \(x\) 回合的选择里是否存在偶/奇数。

\(dp[x][0/1]\) = Elsie 最少需要多少个弹珠才能保证在回合 \(x\) 猜偶/奇数不会输。

转移方程:

\(dp[x][i]=\max\left(1,\min\limits_{j \in \{0,1\}}\{dp[x+1][j]\}+ \begin{cases} \max\limits_{k \in [1,K]}\{a[k] \mid a[k] \not\equiv i \pmod{2} \}, & \text{if} \text{ exist}[x][\neg i] \\ -\min\limits_{k \in [1,K]}\{a[k] \mid a[k] \equiv i \pmod{2} \}, & \text{otherwise} \end{cases}\right)\)

\(\max(1,\cdots)\) 是为了满足弹珠数量在任何回合不能低过 \(1\) 的条件。

边界:\(dp[m+1][0/1]=1\)

目标:

题目要求求出“字典序最小的行动序列”。因为 Even 的字典序小过 Odd,所以优先选择 Even

现在我们已经知道对于所有回合 Elsie 最少应有的弹珠数量。只需遍历 \(1 \le i \le m\),优先选择猜偶数。如果在回合 \(i\) 发现拥有的弹珠数量少于 \(dp[i][0/1]\),那么 Elsie 肯定会输掉游戏,所以输出 \(-1\)


评测记录

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

int main() {
    int t;cin>>t;
    while(t--){
        ll n,m,k;cin>>n>>m>>k;
        bool exist[m+1][2];
        ll maxi[m+1][2],mini[m+1][2];
        memset(exist,0,sizeof(exist));
        memset(maxi,0,sizeof(maxi));
        memset(mini,0,sizeof(mini));
        for(int i=1;i<=m;i++){
            for(int j=0;j<k;j++){
                ll ai;cin>>ai;
                if(exist[i][ai%2]){
                    maxi[i][ai%2]=max(maxi[i][ai%2],ai);
                    mini[i][ai%2]=min(mini[i][ai%2],ai);
                }else{
                    maxi[i][ai%2]=ai;
                    mini[i][ai%2]=ai;
                }
                exist[i][ai%2]=1;
            }
        }

        // dp
        ll dp[m+2][2];
        memset(dp,0,sizeof(dp));
        dp[m+1][0]=1;dp[m+1][1]=1;
        for(int x=m;x>0;x--){
            dp[x][0]=min(dp[x+1][0],dp[x+1][1]);
            if(exist[x][1]) dp[x][0]+=maxi[x][1];
            else dp[x][0]-=mini[x][0];
            dp[x][0]=max(1ll,dp[x][0]);
            
            dp[x][1]=min(dp[x+1][0],dp[x+1][1]);
            if(exist[x][0]) dp[x][1]+=maxi[x][0];
            else dp[x][1]-=mini[x][1];
            dp[x][1]=max(1ll,dp[x][1]);
        }

        //
        bool flag=1;
        string ans="";
        for(int x=1;x<=m;x++){
            if(n<min(dp[x][0],dp[x][1])){flag=0;break;}
            if(ans.length())ans+=" ";
            if(n>=dp[x][0]){
                if(exist[x][1]) n-=maxi[x][1];
                else n+=mini[x][0];
                ans+="Even";
            }else{
                if(exist[x][0]) n-=maxi[x][0];
                else n+=mini[x][1];
                ans+="Odd";
            }
        }
        if(flag)cout<<ans<<'\n';
        else cout<<"-1\n";
    }
}
posted @ 2024-02-28 03:20  lumid  阅读(63)  评论(0)    收藏  举报  来源