C. Make Equal With Mod
题意
给定一个长度为 n 的非负整数数列,可以进行若干次如下操作:
- 选择一个整数 x ( x ≥ 2 ) x\ (x \geq 2) x (x≥2),替换所有位置 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
2≤n≤1018, k≥2
思路
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)+t∗k=2k∗(k+1)+t∗k,其中 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
2≤n≤2⋅105, 1≤k≤109
思路
每次删除之后对其他数产生附加值,但是两个数相减会把其相同的附加值抵消,相减的结果还是原本两数相减的结果。
所以最后剩下的数一定还是数列中两个数相减的结果。
所以判断数列中是否存在两个数相减为 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;
}
经验
像这样的规律为什么不能早点发现呢?