首页 > 其他分享 >Codeforces Round 914 (Div. 2)

Codeforces Round 914 (Div. 2)

时间:2023-12-10 14:56:11浏览次数:48  
标签:std cnt last int move Codeforces tot 914 Div

基本情况

脑子最卡的一集。

A题读假题,卡了快一小时。

B题代码太复杂,出错不好修改,一直调。

虽然最后都出来了,但是没有剩下任何时间看后面题目了。

A. Forked!

Problem - A - Codeforces

一开始不知道犯得什么病,觉得可以斜着走一格算作一步,然后情况就太多了,非常不好处理。

后面突然想着有没有一种可能不能斜着走,然后问题就很简单了。

枚举皇后、国王各自身边的八个位置,看看八个位置中重合的数量即可。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<set>

int move[4][2] = {{1,1},{1,-1},{-1,1},{-1,-1}}; 

void solve()
{
	int a, b, x1, x2, y1, y2, ans = 0;
	std::cin >> a >> b >> x1 >> y1 >> x2 >> y2;
	std::set<std::pair<int, int> > st1, st2;
	for (int i = 0; i < 4; i++)
	{
		st1.insert({x1 + move[i][0] * a, y1 + move[i][1] * b});st1.insert({x1 + move[i][0] * b, y1 + move[i][1] * a});
		st2.insert({x2 + move[i][0] * a, y2 + move[i][1] * b});st2.insert({x2 + move[i][0] * b, y2 + move[i][1] * a});
	}
	for (auto x : st1) if (st2.find(x) != st2.end()) ans++;
	std::cout << ans << std::endl;
}

int main()
{
 	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _; std::cin >> _;
	while(_--) solve(); 
	return 0;
}

B. Collecting Game

Problem - B - Codeforces

最初

显然要用前缀和,但是仅限于此了,再加了几个比较无脑的剪枝,然后T了。

#include <bits/stdc++.h>

int n;
int a[N];
int b[N];
int c[N];
long long s[N];
int ans[N];

bool cmp(int x, int y)
{
	return a[x] < a[y];
}

void solve()
{
	std::cin >> n;
	std::map<int, int> tag;
	std::map<int, long long> sum;
	std::iota(c + 1, c + n + 1, 1);
	s[0] = 0;
	for (int i = 1; i <= n; i++)
		std::cin >> a[i], b[i] = a[i];
	std::sort(c + 1, c + n + 1, cmp);
	std::sort(b + 1, b + n + 1);
	for (int i = 1; i <= n; i++)
		s[i] = s[i - 1] + b[i];
	for (int i = n; i >= 1; i--)
	{
		if (!sum[b[i]])
			sum[b[i]] = s[i] - s[0];//剪枝
	}
	for (int i = n; i >= 1; i--)
	{
		long long tot = sum[b[i]];
		int cnt = i - 1;
		if (tag[b[i]])//剪枝
		{
			ans[c[i]] = tag[b[i]];
			continue;
		}
		for (int j = i + 1; j <= n; j++)
		{
			if (tot >= b[j])
			{
				tot += b[j], cnt++;
			}
		}
		if (!tag[b[i]]) {tag[b[i]] = cnt;ans[c[i]] = cnt;}//剪枝
	}
	for (int i = 1; i <= n; i++)
	{
		std::cout << ans[i] << " ";
	}
	std::cout << std::endl;
}

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _;
	std::cin >> _;
	while (_--)
		solve();
	return 0;
}

优化

观察了一番,感觉这一段有很大的优化空间:

for (int j = i + 1; j <= n; j++)
		{
			if (tot >= b[j])
			{
				tot += b[j], cnt++;
			}
		}

这一段的目的是找到所有的能被删除的数,但是我很朴素地删一个,加一个。

完全可以用二分查找先快速找到最后一个小于等于当前和 \(tot\) 的数,然后直接把当前 \(tot\) 赋成这个数下标的前缀和,然后迭代这个过程,直到无法找到小于等于当前的和 \(tot\) 的数为止即可。

复杂度从 \(\operatorname O(n^2)\) 降到了 \(\operatorname O(n\log_2n)\)。

int t, last_t = i;
while(true)
{
	t = std::upper_bound(b + 1, b + n + 1, tot) - b - 1;
	tot = s[t - 1]; cnt += t - last_t;
	if (last_t == t) break;
 	last_t = t;
}

改错

话虽如此,但是这个代码是错的!导致我调了半天。

t = std::upper_bound(b + 1, b + n + 1, tot) - b - 1;

这玩意求得是第一个大于 \(tot\) 的值的下标。

这是我的第一反应。然后顺着这个思路,自然而然,最后一个小于等于当前 \(tot\) 的元素的下标为 \(t-1\),\(tot = s_{t-1}\)。

然而真正第一个大于 \(tot\) 的下标是 std::upper_bound(b + 1, b + n + 1, tot) 啊喂。

又因为我从 \(1\) 开始存,减去 b+1 这个数组下标一地址之后,实际上返回的是它们之间的差值,说白了,也就是已经是真正第一个大于 \(tot\) 的下标减一了。

所以直接 tot = s[t] 就行了。

但是这样不够优雅。

直接直来直去最明白:

  • 先求第一个大于 \(tot\) 的下标:

    • t =std::upper_bound(b + 1, b + n + 1, tot) - b;
  • 再转成最后一个小于等于 \(tot\) 的下标:

    • t--;
  • 然后直接用就行:

    • while(true)
      		{
      			t = std::upper_bound(b + 1, b + n + 1, tot) - b;
      			t--;
      			tot = s[t]; cnt += t - last_t;
      			if (last_t == t) break;
       			last_t = t;
      		}
      

代码

最后再把之前口胡的剪枝都删掉,搞得简洁一点。

#include <bits/stdc++.h>

int n;
int a[N];
int b[N];
int c[N];
long long s[N];
int ans[N];

bool cmp(int x, int y)
{
	return a[x] < a[y];
}

void solve()
{
	std::cin >> n;
	std::iota(c + 1, c + n + 1, 1);
	s[0] = 0;
	for (int i = 1; i <= n; i++)
		std::cin >> a[i], b[i] = a[i];
	std::sort(c + 1, c + n + 1, cmp);
	std::sort(b + 1, b + n + 1);
	for (int i = 1; i <= n; i++)
		s[i] = s[i - 1] + b[i];
	for (int i = 1; i <= n; i++)
	{
		long long tot = s[i];
		int cnt = i - 1;
		int t, last_t = i;
		while(true)
		{
			t = std::upper_bound(b + 1, b + n + 1, tot) - b;
			t--;
			tot = s[t]; cnt += t - last_t;
			if (last_t == t) break;
 			last_t = t;
		}
		ans[c[i]] = cnt;
	}
	for (int i = 1; i <= n; i++)
	{
		std::cout << ans[i] << " ";
	}
	std::cout << std::endl;
}

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	std::cout.tie(nullptr);
	int _;
	std::cin >> _;
	while (_--)solve();
	return 0;
}

标签:std,cnt,last,int,move,Codeforces,tot,914,Div
From: https://www.cnblogs.com/kdlyh/p/17892647.html

相关文章

  • Codeforces Round 914 (Div. 2)
    C.ArrayGame题意:给定一个n的数组以及k的操作数,每次可以选择下表为i,j(i<j)得到一个abs(a[i]-a[j])的数放在数组末尾,问你k次操作后,数组中最小的数是多少?思路:首先k>=3选相同的下表两次,一定结果是0,是最小。k==1遍历出下表两两相减的绝对值最小以及本身数组中最小的即可k==2要将数......
  • CodeForces 1902F Trees and XOR Queries Again
    洛谷传送门CF传送门如果我们能把\(x\toy\)路径上的所有点权插入到线性基,那么可以\(O(\logV)\)查询。但是因为线性基合并只能\(O(\log^2V)\)(把一个线性基的所有元素插入到另一个),所以只能倍增做\(O((n+q)\logn\log^2V)\),过不了。考虑\(O(n\logV)\)预处理出......
  • Codeforces Round 904 (Div. 2)
    [CodeforcesRound904(Div.2)](https://codeforces.com/contest/1894)A.SimpleDesign暴力就行了1e9跑不满的#include<bits/stdc++.h>#defineintlonglong#defineendl'\n'usingnamespacestd;voidsolve(){intx,k;cin>>x>>......
  • 如何设置div内的模块靠左显示,模块内容按行显示?
    要设置一个div内的模块靠左显示,并且模块内容按行显示,你可以使用CSS中的flexbox布局来实现。以下是一种可能的解决方案:HTML结构:<divclass="container"><divclass="module">模块1</div><divclass="module">模块2</div><divclass="module"&g......
  • Codeforces Round 801 (Div. 2)
    基本情况A就开始犯病,导致+2.B、C都过样例了,但是都错。B.CircleGame赛时推出来奇数必输,也知道偶数不是必赢,但是思路不清楚。这里我没意识到一个很关键的性质。奇数堆拿的石堆会变,这也导致了必输,比如三个堆\(1,2,3\)。表粗的为JOE。123123显然JOE拿的石堆是变化的......
  • [Codeforces] CF1763B Incinerate
    CF1763BIncinerate题意为了消灭人类,怪物协会向地球表面派出了\(n\)只怪兽。第\(i\)只怪物有一个生命值\(h_i\)和一个攻击力\(p_i\).凭借他最后的一击,真螺旋焚烧炮,Genos可以对所有活着的怪物造成\(k\)点伤害。换句话说,Genos可以通过一次攻击降低所有怪物\(k\)点......
  • Codeforces Round 909 (Div. 3)
    https://codeforces.com/contest/1899  一个小游戏#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>usingnamespacestd;intn;intmain(){cin>>n;while(n--){intx;......
  • [Codeforces] CF1704C Virus
    CF1704CVirus题意有一个长度为\(n\)的环,即对于\(1\leqi\leqn\),满足第\(i\)个与第\(i+1\)个房子相邻,特别地,第\(n\)个房子与第\(1\)个房子也相邻。一开始,这\(n\)个房子中有\(m\)个房子被病毒感染了。在之后的每天早上,都可以选择一个未被感染的房子并对其进行保护,被保......
  • [Codeforces] CF1703E Mirror Grid
    CF1703EMirrorGrid题意给定一个\(n\timesn\(n\le100)\)的01矩形,求至少修改多少次后能使矩形旋转0°,90°,180°,270°后所形成的矩形都完全相同。思路吸纳分为两种情况讨论:\(n\)为奇数那么会出现这种情况:(以\(5\times5\)为例)如上图,我们就可以将其分为五个部分,每个......
  • Codeforces Round 811 (Div. 3)
    基本情况ABC秒了。DE都给了我希望,但都做不下去。两道题反复横跳,结果最后谁也没做出来。E还是比D亲切的,先补E吧。E.AddModulo10做的时候想着说对每个个位数的变化找找规律,但是没有进一步的发现。实际上就应该从这里下手。首先共识:相同的两个数经过操作后必然相同。分析......