打卡信奥刷题(3426)用C++实现信奥题 P10192 [USACO24FEB] Moorbles S

P10192 [USACO24FEB] Moorbles S

题目描述

Bessie 和 Elsie 正在玩弹珠游戏。游戏的玩法如下:Bessie 和 Elsie 开始时各有一定数量的弹珠。Bessie 取出 AAA 个弹珠放在蹄子下,Elsie 猜测 AAA 是偶数还是奇数。如果 Elsie 猜对了,她从 Bessie 那里赢得 AAA 个弹珠,如果她猜错了,她输给 Bessie AAA 个弹珠(如果 Elsie 有少于 AAA 个弹珠,她就会输掉所有弹珠)。一名玩家失去所有弹珠时即失败。

游戏进行了一定回合后,Elsie 拥有 NNN1≤N≤1091\le N\le 10^91N109)个弹珠。她感觉获胜很难,但她只是想不要输。在与 Bessie 玩得足够久之后,Elsie 对 Bessie 的习惯有了很好的了解,她发现在回合 iii,Bessie 只可能会取出 KKK1≤K≤41\le K\le 41K4)种不同数量的弹珠。距离 Bessie 感到无聊退出游戏只有 MMM1≤M≤3⋅1051\le M\le 3\cdot 10^51M3105)个回合了。你能求出一个字典序最小的行动序列,使得无论 Bessie 如何选择,Elsie 都不会输吗?

输入格式

输入的第一行包含一个整数 TTT1≤T≤101\le T\le 101T10),为测试用例的数量。每个测试用例的描述如下:

  • 第一行包含三个整数 NNNMMMKKK,分别表示 Elsie 拥有的弹珠数量,回合数及 Bessie 可能进行的选择数。
  • 以下 MMM 行,第 iii 行包含 KKK 个不同的空格分隔的整数 ai,1ai,2…ai,Ka_{i,1}a_{i,2}\ldots a_{i,K}ai,1ai,2ai,K1≤ai,j≤1031\le a_{i,j}\le10^31ai,j103),表示 Bessie 在回合 iii 可能取出的弹珠数量。

输入保证所有测试用例的 MMM 之和不超过 3⋅1053\cdot 10^53105

输出格式

对于每一个测试用例,输出 Elsie 保证不输的字典序最小的行动序列,或者如果她会输则输出 −1−11。行动序列输出在一行中,包含 MMM 个空格分隔的单词,每个单词为 Even(偶)或 Odd(奇)。

注意:Even 的字典序小于 Odd

输入输出样例 #1

输入 #1

2
10 3 2
2 5
1 3
1 3
10 3 3
2 7 5
8 3 4
2 5 6

输出 #1

Even Even Odd
-1

输入输出样例 #2

输入 #2

1
20 8 2
3 5
3 5
3 5
3 5
3 5
3 5
3 5
3 5

输出 #2

Even Even Even Odd Even Odd Even Odd

说明/提示

样例解释 1

在第一个测试用例中,唯一字典序更小的行动序列是 Even Even Even,但 Bessie 可以使 Elsie 输,通过先出 555,将 Elsie 的弹珠数量从 101010 减少到 555,然后再出 333,将 Elsie 的弹珠数量从 555 减少到 222,然后出 333,这会输光她所有的弹珠。

如果 Elsie 采用正确的行动序列 Even Even Odd,那么如果 Bessie 以同样的方式进行游戏,最后当她出 333 时,Elsie 将获得那 333 个弹珠,将她的弹珠数量增加到 555。可以进一步证明,只要 Elsie 操作是 Even Even Odd,Bessie 无法以其他的方式赢走 Elsie 的所有弹珠。

在第二个测试用例中,可以证明,对于 Elsie 可以选择的任何行动顺序,Bessie 都存在一种方式可以赢走 Elsie 的所有弹珠。

测试点性质

  • 测试点 333M≤16M\le 16M16
  • 测试点 4−64-646M≤1000M\le 1000M1000
  • 测试点 7−127-12712:没有额外限制。

C++实现

#include<bits/stdc++.h>
#define int long long
using namespace std;
int T,n,m,k,a[300005],b[300005],dp[300005],suf[300005];
bool ans[300005];
signed main(){
	cin>>T;
	while(T--){
		cin>>n>>m>>k;
		for(int i=1;i<=m;i++)a[i]=b[i]=-1e18;
		for(int j=1;j<=m;j++){
			for(int i=1,x;i<=k;i++){
				cin>>x;
				if(x%2==0)b[j]=max(b[j],-x),a[j]=max(a[j],x);
				else a[j]=max(a[j],-x),b[j]=max(b[j],x);
			}	
		}
		int sum=n;
		for(int i=1;i<=m;i++){
			if(a[i]>b[i])sum-=b[i],ans[i]=0;
			else sum-=a[i],ans[i]=1;
			if(sum<=0)break;
			dp[i]=sum;
		}
		if(sum<=0){
			cout<<-1<<endl;
			continue;
		}
		suf[m]=dp[m];
		for(int i=m-1;i>=1;i--)suf[i]=min(suf[i+1],dp[i]);
		int tot=0;
		for(int i=1;i<=m;i++){
			if(ans[i]==0)continue;
			int tmp=suf[i]+tot;
			tmp=tmp-b[i]+a[i];
			if(tmp>0)tot+=-b[i]+a[i],ans[i]=0;
		}
		for(int i=1;i<=m;i++){
			if(ans[i])cout<<"Odd"<<' ';
			else cout<<"Even"<<' ';
		}
		puts("");
	}
	return 0;
}

在这里插入图片描述

后续

接下来我会不断用C++来实现信奥比赛中的算法题、GESP考级编程题实现、白名单赛事考题实现,记录日常的编程生活、比赛心得,感兴趣的请关注,我后续将继续分享相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值