Loading

Codeforces Round #702 (Div. 3) 全部七题

A. Dense Array

数据范围很小可以直接枚举,对于每个间隔用while循环二倍二倍往里插。

#include <iostream>
using namespace std;
int a[55];
int main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		int n, ans = 0;
		cin >> n;
		for(int i = 1; i <= n; i++) cin >> a[i];
		for(int i = 2; i <= n; i++)
		{
			if(max(a[i], a[i - 1]) * 1.0 / min(a[i], a[i - 1]) > 2.0)
			{
				int tmp = min(a[i], a[i - 1]) * 2;
				ans++;
				while(tmp * 2 < max(a[i], a[i - 1]))
				{
					tmp *= 2;
					ans++;
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

B. Balanced Remainders

模3可以直接分类讨论,如果余数为0的缺数优先贪心地拿余数为2的数加一来补充(如果余数为2的数多的话),其次拿余数为1的数加2来补充(每个代价为2)。

#include <iostream>
using namespace std;
int n, a[30005], ans;
int main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n;
		ans = 0;
		int res[3];
		res[0] = res[1] = res[2] = 0;
		for(int i = 1; i <= n; i++)
		{
			cin >> a[i];
			res[a[i] % 3]++;
		}
		res[0] -= n / 3;
		res[1] -= n / 3;
		res[2] -= n / 3;
		if(res[0] < 0)
		{
			if(res[2] > 0)
			{
				ans += min(-res[0], res[2]);
				if(res[2] >= -res[0])
				{
					res[2] += res[0];
					res[0] = 0;
				}
				else
				{
					res[0] += res[2];
					res[2] = 0;
				}
				
			}
			if(res[0] < 0 && res[1] > 0)
			{
				ans += 2 * min(-res[0], res[1]);
				if(res[1] >= -res[0])
				{
					res[1] += res[0];
					res[0] = 0;
				}
				else
				{
					res[0] += res[1];
					res[1] = 0;
				}
				
			}
			
		}

		if(res[1] < 0)
		{
			if(res[0] > 0)
			{
				ans += min(-res[1], res[0]);
				if(res[0] >= -res[1])
				{
					res[0] += res[1];
					res[1] = 0;
				}


				else
				{
					res[1] += res[0];
					res[0] = 0;
				}
				
			}
			if(res[1] < 0 && res[2] > 0)
			{
				ans += 2 * min(-res[1], res[2]);
				if(res[2] >= -res[1])
				{
					res[2] += res[1];
					res[1] = 0;
				}
				else
				{
					res[1] += res[2];
					res[2] = 0;
				}
				
			}
		}

		if(res[2] < 0)
		{
			if(res[1] > 0)
			{
				ans += min(-res[2], res[1]);
				if(res[1] >= -res[2])
				{
					res[1] += res[2];
					res[2] = 0;
				}


				else
				{
					res[2] += res[1];
					res[1] = 0;
				}
				
			}
			if(res[2] < 0 && res[0] > 0)
			{
				ans += 2 * min(-res[2], res[0]);
				if(res[0] >= -res[2])
				{
					res[0] += res[2];
					res[2] = 0;
				}
				else
				{
					res[2] += res[0];
					res[0] = 0;
				}
				
			}
		}
		cout << ans << endl;
	}
	return 0;
}

C. Sum of Cubes

直接枚举,注意因为开三次根的精度问题进行判定的时候范围要稍微大一点。正负2可以过。

#include <iostream>
#include <cmath>
using namespace std;
long long x;
int main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> x;
		bool flag = 0;
		if(x == 1ll) 
		{
			cout << "NO" << endl;
			continue;
		}
		for(long long a = 1; a * a * a < x; a++)
		{
			long long b0 = pow(x - a * a * a, 1.0 / 3);
			long long b1 = b0 - 1, b2 = b0 + 1, b3 = b0 - 2, b4 = b0 + 2, res = x - a * a * a;
			if(b0 * b0 * b0 == res || b1 * b1 * b1 == res || b2 * b2 * b2 == res || b3 * b3 * b3 == res || b4 * b4 * b4 == res)
			{
				//cout << a << ' ' << b0 << ' ' << b1 << ' ' << b2 << ' ' << endl;
				flag = 1;
				break;
			}
		}
		if(flag) cout << "YES" << endl;
		else cout << "NO" << endl;
	}
	return 0;
}

D. Permutation Transformation

按题意直接搜即可。

#include <iostream>
using namespace std;
int n, a[105], dep[105];
void dfs(int l, int r, int d, int mx_pos)
{
	int mx_r = 0, mx_l = 0, pos_l, pos_r;
	dep[mx_pos] = d;
	if(l >= r) return;
	for(int i = l; i < mx_pos; i++)
	{
		if(a[i] > mx_l)
		{
			mx_l = a[i];
			pos_l = i;
		}
	}
	for(int i = mx_pos + 1; i <= r; i++)
	{
		if(a[i] > mx_r)
		{
			mx_r = a[i];
			pos_r = i;
		}
	}
	if(l <= mx_pos - 1) dfs(l, mx_pos - 1, d + 1, pos_l);
	if(r >= mx_pos + 1) dfs(mx_pos + 1, r, d + 1, pos_r);
}
int main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n;
		int mmax = 0, pos;
		for(int i = 1; i <= n; i++) 
		{
			cin >> a[i];
			if(a[i] > mmax)
			{
				mmax = a[i];
				pos = i;
			}
		}
		dfs(1, n, 0, pos);
		for(int i = 1; i <= n; i++) cout << dep[i] << ' ';
		cout << endl;
	}
	return 0;
}

E. Accidental Victory

因为是完全随机的,又说只要有一点可能都算...所以不妨直接讨论最优情况。首先把所有人按照a的大小排序,求出前缀和数组。可以知道当前的人一定可以干掉值比他小的所有人, 相当于当前的人的a值可以到达sum[i]的大小,然后就看靠这个值能否打败下一个人,再创立一个数组ok, ok[i]=1代表i能打败i+1...然后求出ok的后缀和sub,如果sub[i] == n - i + 1,说明i在打败前i-1个人并获取其值后能接连打败剩下的n-i+1个人(最优情况),满足条件,扔进vector里排序,最后输出即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#define int long long
using namespace std;
struct player
{
	int id, a;
} p[200005];
bool cmp(player aa, player bb)
{
	return aa.a < bb.a;
}
bool cmp1(player aa, player bb)
{
	return aa.id < bb.id;
}
int n;
long long sum[200005];//排序后的前缀和
int sub[200005] = { 0 };
int ok[200005];
signed main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n;
		memset(ok, 0, sizeof(ok));
		for(int i = 1; i <= n; i++)
		{
			cin >> p[i].a;
			p[i].id = i;
		}
		sort(p + 1, p + n + 1, cmp);
		sum[0] = 0;
		for(int i = 1; i <= n; i++)
		{
			sum[i] = sum[i - 1] + p[i].a * 1ll;
			if(sum[i] >= p[i + 1].a * 1ll) ok[i] = 1;
		}
		sub[n] = 1;//第n个一定ok
		for(int i = n - 1; i >= 1; i--)
		{
			sub[i] = sub[i + 1] + ok[i];
		}
		vector<player> v;
		for(int i = 1; i <= n; i++)
		{
			if(sub[i] == n - i + 1) v.push_back(p[i]);
		}
		sort(v.begin(), v.end(), cmp1);
		cout << v.size() << endl;
		for(int i = 0; i < v.size(); i++) cout << v[i].id << ' ';
		cout << endl;
	}
	return 0;
}

F. Equalize the Array

首先先排序。注意到这个题和每个ai的值并没有关系,因此排序后扫一遍数组统计出每个值对应有多少个数。然后把这些数放进vector再排序,从小到大遍历,执行一个类似阶梯里求最大矩形的过程(只不过用不到单调栈),用mmax = max(mmax, v[i] * ((int)v.size() - i));更新最大的矩形面积,再用总的和减去面积就是要删除的元素个数。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int n, a[200005];
int main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n;
		for(int i = 1; i <= n; i++) cin >> a[i];
		sort(a + 1, a + n + 1);
		int cnt = 0;
		vector<int> v;
		a[n + 1] = 0x3f3f3f3f;
		for(int i = 1; i <= n + 1; i++)
		{
			if(i == 1)
			{
				cnt++;
				continue;
			}
			if(a[i] == a[i - 1])
			{
				cnt++;
			}
			else 
			{
				v.push_back(cnt);
				cnt = 1;
			}
		}
		sort(v.begin(), v.end());//类似单调栈,最大矩形
		int mmax = 0, tot = 0;
		for(int i = 0; i < v.size(); i++)
		{
			//cout << v[i] << ' ';
			tot += v[i];
			mmax = max(mmax, v[i] * ((int)v.size() - i));
		}
		//cout << endl;
		cout << tot - mmax << endl;
	}
	return 0;
}

G. Old Floppy Drive

不妨设sum数组为前缀和数组,mx[i]代表前缀和数组里1~i最大的一个前缀和(因为可能有负数,前缀和数组不一定是单调不减,但mx数组一定是单调不减的,所以利用mx数组来进行二分查找)。

如果mx[n] >= x,说明只遍历一遍前缀和数组一定能找到一个位置满足条件,直接在mx用lower_bound二分查找x即可。

如果mx[n] < x:意味着只遍历一轮不够。

首先,如果sum[n] <= 0,说明肯定是越更新越小(联想spfa判负环),永远也不可能停止,直接输出-1.

如果sum[n] > 0,设d = x - mx[n],则至少要循环ceil(d / sum[n])圈。但是向上取整之后在最后一圈就不一定是到mx[n]了,有可能在下标更小的位置就结束循环,这个位置可以根据lower_bound函数查找x - ceil(d * 1.0 / sum[n]) * sum[n],再加上 ceil(d * 1.0 / sum[n]) * n(每轮移动n次)即可。

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define int long long
using namespace std;
int n, m, a[200005];
long long sum[200005], mx[200005];
signed main()
{
	freopen("data.txt", "r", stdin);
	int t;
	cin >> t;
	while(t--)
	{
		cin >> n >> m;
		sum[0] = 0;
		mx[0] = -0x3f3f3f3f;
		for(int i = 1; i <= n; i++) 
		{
			cin >> a[i];
			sum[i] = sum[i - 1] + a[i];
			mx[i] = max(mx[i - 1], sum[i]);
		}
		for(int i = 1; i <= m; i++) 
		{
			long long x;
			cin >> x;
			
			if(mx[n] >= x)
			{
				cout << lower_bound(mx + 1, mx + n + 1, x) - 1 - mx << ' ';
			}
			else
			{
				if(sum[n] <= 0)
				{
					cout << -1 << ' ';
					continue;
				}
				long long d = x - mx[n];
				cout << lower_bound(mx + 1, mx + n + 1, x - sum[n] * (long long)ceil(d * 1.0 / sum[n])) -mx - 1 + (long long)ceil(d * 1.0 / sum[n]) * n << ' ';
				//注意ceil返回的是double 要强制转换一下
			}
		}
		cout << endl;
	}	
	return 0;
}
posted @ 2021-02-18 11:05  脂环  阅读(136)  评论(0编辑  收藏  举报