P10192 [USACO24FEB] Moorbles S 题解
银组只会这题qwq
考虑将奇数和偶数分开计算。如果 Elsie 在回合 \(i\) 猜奇数,那么对 Elise 的最坏可能是:
- 存在偶数
Bessie 把 \(a_{i,1},a_{i,2},\dots,a_{i,K}\) 中最大的偶数放在蹄子下。Elsie 的弹珠数量减去该数。
- 不存在偶数
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";
}
}

浙公网安备 33010602011771号