Codeforces Round #748 (Div. 3) A-E

A. Elections
题意就是给你三个数,然后让你求出要超过其他两个数,他需要再加多少。
就是判断出所有情况即可。
如果三个数都相同的时候 就都只需要加1。
如果两个数相同并且大于另外一个数,则这两个数需要加1,而另外一个数则需要加他们的差值再加1。
三个数都不同就是和最大值有关了。除了最大的那个数本身不需要再加1,其他两个数都需要加差值再加1.

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
int n, m, T;
int flag;

int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--) {
		ll a, b, c;
		cin >> a >> b >> c;
		if (a == b && b == c) {
			cout << 1 << " " << 1 << " " << 1 << endl;
			continue;
		}
		ll maxn = max(a, max(b, c));
		if (a == b && a == maxn) {
			cout << 1 << " " << 1 << " " << maxn - c+1<< endl;
			continue;
		} else if (a == c && a == maxn) {
			cout << 1 << " " << maxn - b+1 << " " << 1 << endl;
			continue;
		} else if (b == c && b == maxn) {
			cout << maxn - a +1<< " " << 1 << " " << 1 << endl;
			continue;
		}
		cout << (maxn - a ? maxn - a + 1 : 0) << " " << (maxn - b ? maxn - b + 1 : 0) << " "
			 << (maxn - c ? maxn - c + 1 : 0) << endl;
	}
	return 0;
}

B. Make it Divisible by 25
题意是给你一个数,看你最少删去几个数可以让他变成25的倍数,题目保证有解且没有前导零。
因为要是25的倍数,所以我们可以观察下25倍数的特征,即后面两个数字只有25,50,75,00。这四种情况。所以我们就是遍历这四种情况即可。
我是字符串读入,然后翻转一下。就把找四种情况变成了找两种情况。
即如果当前位是0 就往后找5和0.
如果当前位数是5就往后找2和7.
然后如果找到了就求出需要减去几位,记录最小值即可。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
int n, m, T;
int flag;

int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--) {
		// ll a;
		// cin>>a;
		string s;
		cin >> s;
		reverse(s.begin(),s.end());
		// cout<<s<<endl;
		int len = s.size();
		int ans=100;
		for (int i = 0; i < len; i++) {
			if(s[i]=='0'){
				for(int j=i+1;j<len;j++){
					if(s[j]=='0'||s[j]=='5'){
						ans=min(j-1,ans);
						break;
					}
				}
			}else if(s[i]=='5'){
				for(int j=i+1;j<len;j++){
					if(s[j]=='2'||s[j]=='7'){
						ans=min(j-1,ans);
						break;
					}
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

C. Save More Mice
简单贪心。很显然,让先靠近洞的老鼠先走是最好的,因为如果你让后面的老鼠先走,那么他走到洞口需要的步数会比前面的老鼠多。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf=0x3f3f3f3f;
const int MAXN=4e5+10;
int n,m,T;
int flag; 

int a[MAXN];
int main() 
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n>>m;
		for(int i=1;i<=m;i++){
			cin>>a[i];
		}
		sort(a+1,a+1+m);
		int num=0;
		ll b=0;
		for(int i=m;i>0;i--){
			if(b<a[i]){
				num++;
				b+=n-a[i];
			}else{
				break;
			}
		}
		cout<<num<<endl;
	}
	return 0;
}

D1. All are Same
因为是简化版本,所以暴力也能过。
因为是减去一个数k次,使得所有的数相同,显然就是一个同余的问题。
因为最小值减去这个数就相当于每个数都再减一遍这个数,没有什么意义,所以可以吧最小值当基准,每个数减去最小值得到的数,就是他们需要通过减去某个数而减到0的数。
即转化成了差值的最大公因数。(我的代码是直接暴力每个数都求一下,因为看着暴力就过了,就没多想了)。
然后所有数都相同的情况特判一下就行了。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf=0x3f3f3f3f;
const int MAXN=1e5+10;
int n,m,T;
int flag; 

int a[MAXN];
int main() 
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>T;
	while(T--){
		cin>>n;
		for(int i=1;i<=n;i++){
			cin>>a[i];
		}
		sort(a+1,a+1+n);
		if(a[1]==a[n]){
			cout<<-1<<endl;
			continue;
		}
		int v;
		int ans=0;
		for(int i=1;i<=a[n]-a[1];i++){
			flag=1;
			for(int j=1;j<=n;j++){
				if((a[j]-a[1])%i){
					flag=0;
					break;
				}
			}
			if(flag){
				ans=max(ans,i);
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}

D2. Half of Same
D2和D1的区别就是 ,D2只需要一半的数相同就行了。
所以我们就是以某个数为基准,即以他为最小值,然后遍历后面数的差值。
找到这个差值的因子,check一下。
即检查下后面是否有一半即以上的数可以相同。更新最大值即可。
然后记得特判即可。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
int n, m, T;
int flag;

ll a[105];

bool check(int x, int d)
{
	int cnt = 0;
	for (int i = x; i <= n; i++) {
		if ((a[i] - a[x]) % d == 0) {
			cnt++;
		}
	}
	return cnt >= n / 2;
}
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--) {
		cin >> n;
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
		}
		sort(a + 1, a + 1 + n);
		flag = 0;
		for (int i = 1; i <= n; i++) { //特判
			if(flag){
				break;
			}
			for (int j = i+1; j <= n; j++) {
				if (a[i] == a[j]&&j-i+1>=n/2) {
					cout << -1 << endl;
					flag = 1;
					break;
				}
			}
		}
		if (flag)
			continue;
		int ans = 0;
		for (int i = 1; i <= n / 2 + 1; i++) {
			for (int j = i + 1; j <= n; j++) {
				int d = a[j] - a[i];
				for (int k = 1; k * k <= d; k++) {
					if (d % k != 0)
						continue;
					if (check(i, d / k))//先判断d/k  因为d/k大于等于k 如果d/k可以就不需要判断k了
						ans = max(ans, d / k);
					else if (check(i, k))
						ans = max(ans, k);
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

E. Gardener and Tree
就是相当于是求每个点的深度的问题。
那么怎么求每个点的深度呢。
我们一开始遍历整个图。
当某个点他只连了一条边或者,一条边都没有连的时候,就是深度为1的点。
而当我将这些点移除,再遍历一遍这个图。同样的,连了一条或者没连的是深度为2的点。
但是我们一遍一遍的遍历整个图,肯定会超时。
所以我们换个方式,直接将每个点连的边的条数记录下来。然后如果某个点的边被移除后,导致他的边数小于等于1那么他的深度就是这个点的深度加1。

#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define endl '\n'
const int inf = 0x3f3f3f3f;
const int MAXN = 4e5 + 10;

int n, m, T;
int k;
int flag;
vector<int> sd(MAXN),bnum(MAXN);
vector<int> v[MAXN];
int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> T;
	while (T--) {
		cin >> n >> k;
		for(int i=0;i<n;i++){
			v[i].clear();
		}
		for (int i = 1; i <n; i++) {
			int x, y;
			cin >> x >> y;
			x--;
			y--;
			v[x].push_back(y); //存放无向图
			v[y].push_back(x);
		}
		queue<int> q;
		for (int i = 0; i < n; i++) {
			sd[i] = inf;			  //看他是第几次 修剪会被减去
			bnum[i] = v[i].size(); //看他连了几条边
			if (bnum[i] <= 1) {	  //如果他只连了一条边 那么说明这个点是叶节点
								//之所以要判断小于等于0 是因为 只有一个节点的时候, 第一次裁剪完就没有叶结点了
				sd[i] = 1;
				q.push(i);
			}
		}
		while (!q.empty()) {
			int x = q.front();
			q.pop();
			for (auto y : v[x]) {
				if (bnum[y]-- == 2) {
					sd[y] = sd[x] + 1;
					q.push(y);
				}
			}
		}
		int ans = 0;
		for (int i = 0; i < n; i++) {
			if (sd[i] >k) {
				ans++;
			}
		}
		cout << ans << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值