首页 > 其他分享 >2022CCPC威海J. Eat, Sleep, Repeat(博弈/思维)

2022CCPC威海J. Eat, Sleep, Repeat(博弈/思维)

时间:2022-11-10 12:13:12浏览次数:42  
标签:Repeat 限制 2022CCPC int pos back Sleep mp 数组

题目大意是给定长度为n的数组a,两个人轮流从中选一个正数将其减1。且有k个限制形如\(limit_{x_i}= y_i\),即\(x_i\)在数组中最多出现\(y_i\)次。判负的情况为:

  1. 数组全为0

  2. 操作后的数组不满足某个限制。

问谁会赢。

首先可以手玩一下,设数组为 \(a = [3, 4]\),\(limit_2=1\),先手选3,数组变为\([2, 4]\),此时仍然满足限制,此时第一种情况是后手选4,数组变成\([2, 3]\),这时限制永远也不会起作用了;第二种情况是后手选2,数组变为\([1, 4]\),原本已经卡紧的限制又放开了。这样可以观察出,如果一条限制的\(y_i\)不为0,那么不会有人傻到主动去让自己输掉,同时也没法给别人挖坑,除非有一种情况:

1
5 2
5 5 5 5 5
2 0
3 2

因为不能把数减为2,所以最多也就只能减到3,这时\(limit_3=2\)这个限制就没法绕过去了。所以可以把限制按\(y_i=0\)分段,每段中让属于这一段的数尽可能小(操作数是固定的),先把一开始连续若干个限制填满,剩下的数再尽可能小。这样算出总的操作次数,为奇则先手胜。可以额外设置\(limit_{-1}=0\),避免冗长的特判。

#include <bits/stdc++.h>
#define int long long
#define de cout<<"fuck"<<endl;
using namespace std;
int n, k, a[100005], x[100005], y[100005], sum[100005];
void solve() {
	cin >> n >> k;
	int mx = 0;
	map<int, int> mp;//存放限制
	for(int i = 1; i <= n; i++) {
		cin >> a[i];
		mx = max(mx, a[i]);
	}
	sort(a + 1, a + n + 1);
	for(int i = 1; i <= n; i++) {
		sum[i] = sum[i - 1] + a[i];
	}
	vector<int> v, r;//v:存放y值为0的限制x r:存放所有的限制x
	v.push_back(-1);
	r.push_back(-1);
	for(int i = 1; i <= k; i++) {
		cin >> x[i] >> y[i];
		if(y[i] == 0) {
			v.push_back(x[i]);
		}
		mp[x[i]] = y[i];
		r.push_back(x[i]);
	}
	if(k == 0) {
		if(sum[n] & 1) puts("Pico");
		else puts("FuuFuu");
		return;
	}
	v.push_back(mx + 1);
	r.push_back(mx + 1);
	sort(v.begin(), v.end());
	sort(r.begin(), r.end());
	mp[-1] = 0;
	mp[mx + 1] = 0;
	int tot = 0;
	for(int i = 0; i < v.size() - 1; i++) {
		int L = v[i], R = v[i + 1] - 1;
		//找[L, R]这段区间的限制以及所有的数组的数
		int pl1 = lower_bound(r.begin(), r.end(), L) - r.begin();
		int pr1 = lower_bound(r.begin(), r.end(), R) - r.begin();//此时的r[pr1]对应的是下一个区间的起点 因此要减一
		pr1--;
		int pl2 = lower_bound(a + 1, a + n + 1, L) - a;
		int pr2 = upper_bound(a + 1, a + n + 1, R) - a - 1;
		if(!(pl2 <= pr2 && pl2 >= 1 && pl2 <= n && pr2 >= 1 && pr2 <= n)) {
			continue;//这段区间没有数
		}
		if(pl1 == pr1 || r[pl1] + 1 < r[pl1 + 1]) {
			//这段区间起作用的限制只有一开始的limit r[pl1] = 0 直接把所有数操作为 r[pl1]+1即可
			tot += (sum[pr2] - sum[pl2 - 1] - (pr2 - pl2 + 1) * (v[i] + 1));
		} else {
		 	//1
			//5 2
			//5 5 5 5 5
			//2 0
			//3 2
			//4 1
			int pos = pl1;
			int lst_consec;
			pos++;//r[pos]这个限制的y为0 跳过
			for(int j = pl2; j <= pr2; j++) {
				//a[j]是当前数
				if(pos > pr1 || (r[pos] - r[pos - 1]) > 1) {//从一开始的连续的限制已经都填满了 剩下的数都减到r[lst_consec]+1即可
					tot += (a[j] - (r[lst_consec] + 1));
					continue;
				}
				lst_consec = pos;
				if(mp[r[pos]] != 0) {//如果有空位就填
					mp[r[pos]]--;
					tot += (a[j] - r[pos]);
				}
				if(mp[r[pos]] == 0) {
					pos++;
				}
			}

		}
	}
	if(tot & 1) puts("Pico");
	else puts("FuuFuu");
}
signed main() {
	int T = 1;
	cin >> T;
	while(T--) {
		solve();
	}
	return 0;
}

标签:Repeat,限制,2022CCPC,int,pos,back,Sleep,mp,数组
From: https://www.cnblogs.com/lipoicyclic/p/16876635.html

相关文章

  • sleepyHolder_hitcon_2016
    sleepyHolder_hitcon_2016今天才开通博客,欢迎各位大佬光临>_<正好今天才做好一个有关unlink的题,(几个月前才学过,由于本人太菜,再加上栈没学好,学过之后就在作栈题,正好zikh......
  • [LeetCode] 1668. Maximum Repeating Substring
    Forastring sequence,astring word is k-repeating if word concatenated k timesisasubstringof sequence.The word's maximum k-repeatingvalue......
  • Leetcode第1668题:最大重复子字符串(Maximum repeating subarray)
    解题思路题目条件字符串长度不超过100,直接从大到小枚举word的重复次数k,判断word重复次数后是否还是sequence的字串,是就直接返回重复次数k。核心代码如下:classSolution......
  • np.repeat()
    np.repeat用于将numpy数组重复一维数组重复三次importnumpyasnp#随机生成[0,5)之间的数,形状为(1,4),将此数组重复3次pop=np.random.randint(0,5,size=(1,4))......
  • 2022CCPC(桂林)
    我的首站本来想着练练手拿铜牌血赚打铁不亏结果保底铜牌要是G题做出来应该可以冲击一下银牌https://codeforces.com/gym/104008A.Lily签到题:所有不在L旁的字符......
  • CH582开启睡眠模式(LowerPowerSleep)下低功耗测试
             上图为手册中在睡眠模式下的功耗值,以此为参考依据。GPIOA_ModeCfg(GPIO_Pin_All,GPIO_ModeIN_PU);GPIOB_ModeCfg(GPIO_Pin_All,......
  • SQL注入--根据sleep判断
    找数据库名1'unionselectsleep(5),2wheredatabase()like'{数据库名称枚举}%';--union是联合查找数据库,当查询为真是sleep生效‘;--’能注释其余SQL找表名1'......
  • C语言演示多个字符从两端向中间汇聚(Sleep、system函数的简单使用)
    一.问题描述效果图: 二.解题思路我们可以定义两个数组,一个数组存储字符串,一个数组存储‘#’,再来一个循环将两个数组的元素从两端开始进行互换,直至全部换完就得到了完整的字......
  • shell sleep 睡眠命令
    shellsleep睡眠文章目录​​shellsleep睡眠​​​​1.背景​​​​2.简介​​​​3.语法​​​​4.实例​​​​4.1设置警报​​​​4.2终端中的延迟命令​​​​......
  • 关于sleep和定时器
    平时使用sleep多一些,如缓冲满了,等一会再送。while(缓冲满了){sleep(MS)};某个任务,20毫秒执行一次, while(TRUE){ 做任务(用了1毫秒),sleep(18,19毫秒)};几乎很少使用定时器;也感觉不出......