2024牛客多校3

Dominoes!

将牌的存放分为x==y和x!=y两堆,从左到右依次放置x==y和x!=y的牌堆

对于x==y 的牌(总数记为sum),找到出现次数最多的k,讨论k的存放位置

对于x!=y的牌,容易实现相邻两个牌上的数字不同,即对于每个牌上的数字(x,y)(令x<y),以x为第一关键字进行升序,再以y为第二关键字进行升序,排序完后交换每张牌中x,y的位置(若输入中存在x==y的牌,则需将含有k的x!=y的牌放置至牌堆的最前面,以保证两个牌堆相连处不会出现相邻两个牌上数字相同的情况)

若sum>2*k,必然存在一种方式,使得相邻两个牌上的数字不同。按照剩余牌数从高到低依次向左侧放置,且需保证相邻两张上的数字不同

若(sum+1)/2==k,在两张数字为k的牌中插入一张其他数字的牌即可

若2*k>sum,参照上一种放置方式,并将剩余的牌插入到x!=y的牌堆中,且保证相邻两个牌上的数字不同,若无法实现,输出NO

code

int maxsame = 0;
bool cmp(pii a, pii b) {
	if (a.first == maxsame || a.second == maxsame)	{
		if (b.first != maxsame && b.second != maxsame)
			return 1;
		else
			return a.first + a.second - maxsame < b.first + b.second - maxsame;
	}
	if (b.first == maxsame || b.second == maxsame){
		if (a.first != maxsame && a.second != maxsame)
			return 0;
		else
			return a.first + a.second - maxsame < b.first + b.second - maxsame;
	}
	if (a.first == b.first)
		return a.second < b.second;
	return a.first < b.first;
}
void solve() {
	int n;
	cin >> n;
	int samesum = 0;
	vector<pii> pa,ans;
	map<int, int>mp;
	for (int i = 0; i < n; i++) {
		int x, y;
		cin >> x >> y;
		if (x > y)
			swap(x, y);
		if (x == y) {
			mp[x]++;
			samesum++;
			if (mp[x] > mp[maxsame])
				maxsame = x;
		}
		else
			pa.push_back({ x,y });
	}
	sort(pa.begin(), pa.end(),cmp);
	if (mp[maxsame] == (samesum+1) / 2) {
		for (auto u : mp) {
			if (u.first == maxsame)
				continue;
			for (int i = 0; i < u.second; i++) {
				ans.push_back({ maxsame,maxsame });
				ans.push_back({ u.first,u.first });
			}
		}
		if (samesum % 2)
			ans.push_back({ maxsame,maxsame });
		else
			reverse(ans.begin(),ans.end());
		for (auto u : pa){
			if (u.second == maxsame) 
				ans.push_back({ u.first,u.second });
			else
				ans.push_back({ u.second,u.first });
		}
	}
	else if (mp[maxsame] * 2 > samesum) {
		for (auto u : mp) {
			if (u.first == maxsame)
				continue;
			for (int i = 0; i < u.second; i++) {
				ans.push_back({ maxsame,maxsame });
				ans.push_back({ u.first,u.first });
				mp[maxsame]--;
			}
		}
		ans.push_back({ maxsame,maxsame });
		mp[maxsame]--;

		for (auto u : pa) {
			if (u.second == maxsame)
				ans.push_back({ u.first,u.second });
			else
				ans.push_back({ u.second,u.first });
			if (mp[maxsame]&&u.first != maxsame && u.second != maxsame){
				ans.push_back({ maxsame,maxsame });
				mp[maxsame]--;
			}
		}
		if (mp[maxsame]) {
			cout << "NO\n";
			return;
		}
	}
	else {
		ans.push_back({ maxsame,maxsame });
		mp[maxsame]--;
		priority_queue<pii> q;
		for (auto u : mp){
			if (u.second != 0)
				q.push({ u.second,u.first });
		}
		int pre = maxsame;
		while (!q.empty()) {
			pii u = q.top();
			q.pop();
			if (u.second == pre) {
				pii uu = q.top();
				q.pop();
				q.push({ u.first,u.second });
				ans.push_back({ uu.second,uu.second });
				if(uu.first!=1)
					q.push({ uu.first - 1,uu.second });
				pre = uu.second;
			}
			else {
				ans.push_back({ u.second,u.second });
				pre = u.second;
				if(u.first!=1)
					q.push({ u.first - 1,u.second });
			}
		}
		reverse(ans.begin(), ans.end());

		for (auto u : pa) {
			if (u.second == maxsame)
				ans.push_back({ u.first,u.second });
			else
				ans.push_back({ u.second,u.first });
		}
	}
	cout << "YES\n";
	for (auto u : ans)
		cout << u.first << ' ' << u.second << '\n';
}

Rigged Games

每一个字符代表一小局的胜负情况,每赢a个小局代表赢一个大局,赢b个大局代表最终的胜利

遍历字符串s,记录从每个字符开始赢一个大局的结束位置

倍增记录从每个开始赢2^k(0<=k<20)个大局的结束位置

最后对b按二进制位进行拆分,记录从每个位置开始赢2*b-1个大局后,两位玩家分别获胜的次数

code

int stp[100010][20];
int ans[100010][20];
void solve() {
	int n, a, b;
	cin >> n >> a >> b;
	int i = 0, j = 0;
	string s;
	cin >> s;
	int l = 0, r = 0, x = 0, y = 0;
	while (l < n) {
		if (x == a || y == a) {
			stp[l][0] = r;
			ans[l][0] = (x == a ? 1 : 0);
			s[l] == '1' ? x-- : y--;
			l++;
			continue;
		}
		s[r] == '1' ? x++ : y++;
		r = (r + 1) % n;
	}
	for (j = 1; j < 20; j++) {
		for (i = 0; i < n; i++) 
			stp[i][j] = stp[stp[i][j - 1]][j - 1];
	}
	for (j = 1; j < 20; j++) {
		for (i = 0; i < n; i++) 
			ans[i][j] = ans[i][j - 1] + ans[stp[i][j - 1]][j - 1];
	}
	for (i = 0; i < n; i++) {
		int tmp = 0, loc = i;
		for (j = 0; j < 20; j++) {
			if (((2 * b - 1) >> j) & 1) {
				tmp += ans[loc][j];
				loc = stp[loc][j];
			}
		}
		tmp >= b ? cout << '1' : cout << '0';
		tmp = 0;
	}
	cout << "\n";
}

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值