CodeTON Round 1 (Div. 1 + Div. 2) - B, C, D

C. Make Equal With Mod

题意
给定一个长度为 n 的非负整数数列,可以进行若干次如下操作:

  • 选择一个整数 x   ( x ≥ 2 ) x\ (x \geq 2) x (x2),替换所有位置 a i a_i ai a i   m o d   x a_i\ mod\ x ai mod x

问,是否能将数列中所有元素变为相同的?

思路
忽略到一点:可以模上元素本身!!

每次操作可以让模上数列中的最大值,让数列中的最大值变为 0。
这样,所有大于等于 2 的元素都可以变为 0。但如果数列中有 1 存在的话,就无法将 1 也变为 0。

  • 如果数列中不存在 1,那么一定满足;
  • 如果数列中只存在 1,不存在 0,可以让所有元素都模上其本身 -1,这样所有数都变为 1,除了存在有两个大小相邻的元素;
  • 如果数列中有 1 也有 0,那么无论如何都不能变为相同;

Code

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){
	Ios;
	cin >> T;
	while(T--)
	{
		cin >> n;
		int f0 = 0, f1 = 0;
		for(int i=1;i<=n;i++)
		{
			cin >> a[i];
			if(a[i] == 0) f0 = 1;
			if(a[i] == 1) f1 = 1;
		}
		
		if(f0 && f1) cout << "NO\n";
		else if(!f0 && f1){
			sort(a+1, a+n+1);
			int flag = 0;
			for(int i=2;i<=n;i++)
				if(a[i] == a[i-1]+1) flag = 1;
			if(flag) cout << "NO\n";
			else cout << "YES\n";
		}
		else cout << "YES\n";
	}
	
	return 0;
}

经验
场上一直在想,到底是模几啊,是 2, 3, 5, 7 就行么?想了半天发现有反例,然后就卡住了。。
一直没想到可以模上自己。。

一定要先考虑特殊的情况啊!


D. K-good

题意
给定一个数 n n n,判断是否可以分解成 k k k 个正整数,并且这 k k k 个数 % k \%k %k 的余数各不相同。
如果可以,输出 k k k;否则输出 − 1 -1 1
2 ≤ n ≤ 1 0 18 ,   k ≥ 2 2 \leq n \leq 10^{18},\ k \geq 2 2n1018, k2

思路
k 个正整数,%k 的余数各不相同,说明这 k 个数一定分别包含 1, 2, …, k,再加上 t 倍的 k。
那么 n = ( 1 + 2 + . . . + k ) + t ∗ k = k ∗ ( k + 1 ) 2 + t ∗ k n = (1+2+...+k) + t*k = \frac {k*(k+1)}{2} + t*k n=(1+2+...+k)+tk=2k(k+1)+tk,其中 t 为非负整数。
化简后得: 2 n = k ∗ ( k + 1 + 2 t ) 2n = k*(k+1+2t) 2n=k(k+1+2t)
2 t 2t 2t 为偶数,那么 k k k k + 1 + 2 t k+1+2t k+1+2t 一定为一奇一偶。
那么就是看 2 n 2n 2n 能否分解为一奇一偶。分解之后较小的那个便是 k。1除外。

Code

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){
	Ios;
	cin >> T;
	while(T--)
	{
		cin >> n;
		n *= 2;
		int cnt = 0, x = 1;
		while(n % 2 == 0)
		{
			n /= 2;
			cnt++;
			x *= 2;
		}
		int ans = min(n, x);
		if(ans != 1) cout << ans << endl;
		else cout << -1 << endl;
	}
	
	return 0;
}

经验
题目要看仔细,一开始没注意到 k 不能为 0,把 k 个数认为是 0 到 k-1 了。
化简式子的题目做的少,不能看出来规律。。多积累吧。


B. Subtract Operation

题意
给定 n n n 个数,每次选择一个数 x x x 删掉,其余所有数都减去 x x x
问,最后一个元素能否为 k k k
2 ≤ n ≤ 2 ⋅ 1 0 5 ,   1 ≤ k ≤ 1 0 9 2 \leq n \leq 2\cdot 10^5,\ 1 \leq k \leq 10^9 2n2105, 1k109

思路
每次删除之后对其他数产生附加值,但是两个数相减会把其相同的附加值抵消,相减的结果还是原本两数相减的结果。
所以最后剩下的数一定还是数列中两个数相减的结果。
所以判断数列中是否存在两个数相减为 k 即可。

Code

#include<bits/stdc++.h>
using namespace std;

#define Ios ios::sync_with_stdio(false),cin.tie(0)
#define int long long

const int N = 200010, mod = 1e9+7;
int T, n, m;
int a[N];

signed main(){
	Ios;
	cin >> T;
	while(T--)
	{
		cin >> n >> m;
		mp.clear();
		for(int i=1;i<=n;i++) cin >> a[i], mp[a[i]] = 1;
		
		int flag = 0;
		for(int i=1;i<=n;i++)
		{
			if(mp[a[i] - m]) flag = 1;
		}
		if(flag) cout << "YES\n";
		else cout << "NO\n";
	}
	
	return 0;
}

经验
像这样的规律为什么不能早点发现呢?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值