zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    ansible管理windows实践
    SQL server 备份/恢复/压缩 进度查询
    什么是容器
    pycharm 快捷键
    SUSE Linux--zypper程序包管理(实战命令总结)
    源码编译安装
    CentOS-yum基本使用
    rpm管理
    btrfs的精简总结版
    btrfs的介绍与使用
  • 原文地址:https://www.cnblogs.com/lipoicyclic/p/14411008.html
Copyright © 2011-2022 走看看