Codeforces Round #698 (Div. 2)A,B,C,D,F
A - Nezzar and Colorful Balls
题意
有 n n n 个球,第 i i i 个球上的序号是 a i a_i ai ,保证对任意 a i a_i ai 都有 a i ≤ a i + 1 a_i \leq a_{i+1} ai≤ai+1 。现在你要给球涂上颜色,保证在球按照颜色分开后,每种颜色的球序号从小到大是严格递增的,也就是只考虑某种颜色的球的情况下,对相邻的 a i a_i ai、 a j a_j aj,均有 a i < a i + 1 a_i \lt a_{i+1} ai<ai+1 。问最少需要几种颜色,能达到这个要求?
思路
问题可以化为:原数组中有可能有多个重复相同的数字,分开后的数组中不能有重复相同的数字。因此,只需要找到原数组所有元素中出现次数最多的即可。
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e6 + 9;
const ll mod = 1e9 + 7;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
int nowcnt = 0;
int maxc = 0;
int nowx = 0;
for(int i = 0; i < n; i++)
{
int x;
scanf("%d", &x);
if(x != nowx)
{
maxc = max(maxc, nowcnt);
nowx = x;
nowcnt = 1;
}
else
{
nowcnt++;
}
}
cout << max(maxc, nowcnt) << endl;
}
return 0;
}
B - Nezzar and Lucky Number
题意
在1~9中,李华最喜欢的数字是 d d d 。如果一个正整数在其十进制表示下含有 d d d ,则李华称之为幸运数字。现给定一些数字,问你他们能否被分解为几个(一个或多个)幸运数字相加?
思路
- 如果数字 x x x 大于等于 10 × d 10 \times d 10×d ,则 x x x 一定可以分解成 x = ( k 1 × 1 0 m + d ∗ 10 + k 2 ) + ( k 3 × 10 + d ) x = (k_1 \times10^m + d*10 + k_2) + (k_3 \times 10 + d) x=(k1×10m+d∗10+k2)+(k3×10+d) 的形式( k i k_i ki 是任意正整数),这两个数都含有数字d(一个在十位一个在个位);
- 在数字 x x x 小于 10 × d 10 \times d 10×d 的情况下,则 x x x 若能被分解,一定有 x = k 1 × 10 + k 2 × d x = k_1 \times 10 + k_2 \times d x=k1×10+k2×d,因此只需要判断 x x x 的个位是否与某一个 d d d 的倍数的个位相同即可。
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e6 + 9;
const ll mod = 1e9 + 7;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
int q, d;
scanf("%d%d", &q, &d);
for(int i = 0; i < q; i++)
{
bool flag = 0;
ll x;
scanf("%lld", &x);
if(x >= 10 * d)
{
printf("YES\n");
continue;
}
int tmp = x % 10;
for(int i = 1; i < 10; i++)
{
if(i * d > x)
break;
if(i * d % 10 == tmp)
{
flag = 1;
break;
}
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
}
return 0;
}
C - Nezzar and Symmetric Array
题意
数组 a a a 中有 2 n 2n 2n 个整数,且数组中的元素满足,若 a i a_i ai 在数组中,则必有且仅有一个 a j = a i a_j = a_i aj=ai,即每个数的相反数都在其中。现给定一个数组 d d d ,其中 d i = ∑ j = 1 n ∣ a i − a j ∣ d_i = \sum_{j = 1}^n |a_i - aj| di=∑j=1n∣ai−aj∣,问能不能推出一个满足要求的数组 a a a ?无需输出 a a a 的内容,只需要判断。
思路
参考:
Codeforces Round #698 (Div. 2)-C. Nezzar and Symmetric Array-题解
Codeforces Round #698 (Div. 2)_
我们可以思考: d d d 和 a a a 有哪些相关的特性?
- a a a 的每一个元素在 d d d 中对应位置的值,与他的相反数在 d d d 中对应位置的值,都是相等的。这点可以通过假设法证明(假设有 a < b < c ( a , b , c > 0 ) a < b < c(a,b,c \gt 0) a<b<c(a,b,c>0),计算 a a a 和 − a -a −a , b b b 和 − b -b −b , c c c 和 − c -c −c 在 d d d 中的值);
- 对于任意的 a i a_i ai ,其与除自身外的任意元素 a j a_j aj ,都有 ∣ a i − a j ∣ + ∣ a i − ( − a j ) ∣ |a_i - a_j| + |a_i - (-a_j)| ∣ai−aj∣+∣ai−(−aj)∣ 的值一定是偶数(分类讨论或者画图一下即可);
- 原本的每一个数都是整数;
- 若只考虑正整数(或只考虑负整数),每一个数都是独特的,没有重复。这点可以合并到第1点去(见下面的概括)。
综上,我们可以把特性概括/衍生为以下几点:
- d d d 中每个元素的值出现且仅出现两次(第一点+第四点);
- d d d 中的每个元素都是偶数;
- 原本的数都是整数。
第一点和第二点通过map来实现,因为数据范围1e9,数组存不下;
第三点,我们分类讨论一下,对于任意的 ∣ a i − a j ∣ + ∣ a i − ( − a j ) ∣ |a_i - a_j| + |a_i - (-a_j)| ∣ai−aj∣+∣ai−(−aj)∣ ,如果 a i > a j a_i \gt a_j ai>aj,则 ∣ a i − a j ∣ + ∣ a i − ( − a j ) ∣ = 2 a i |a_i - a_j| + |a_i - (-a_j)| = 2a_i ∣ai−aj∣+∣ai−(−aj)∣=2ai;若 a i < a j a_i \lt a_j ai<aj,则 ∣ a i − a j ∣ + ∣ a i − ( − a j ) ∣ = 2 a j |a_i - a_j| + |a_i - (-a_j)| = 2a_j ∣ai−aj∣+∣ai−(−aj)∣=2aj。所以其实 d i d_i di就是 2 × ∑ j = 0 n m a x ( a i , a j ) 2 \times \sum_{j = 0}^n max(a_i, a_j) 2×∑j=0nmax(ai,aj),即 a i a_i ai 和其他所有正整数比较后最大的那个正整数的两倍,所以在已知 d i d_i di的情况下, a i = ( d i / 2 − s u m / n ) a_i = (d_i/2- sum/n) ai=(di/2−sum/n),其中 s u m = ∑ a j , a j > a i sum = \sum a_j, a_j \gt a_i sum=∑aj,aj>ai 。所以从大到小不重复的遍历所有 d i d_i di,将当前元素减去之前已经算出的元素(因为是从最大开始算,所以 s u m sum sum 的值其实就是之前元素的累加),再除以还剩下几个元素,判断是否能整除(且大于0)即可。
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e6 + 9;
const ll mod = 1e9 + 7;
map<ll, int> mp;
priority_queue<ll> que;
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
mp.clear();
while(!que.empty())
que.pop();
int n;
scanf("%d", &n);
for(int i = 0; i < 2 * n; i++)
{
ll x;
scanf("%lld", &x);
mp[x]++;
}
bool flag = true;
for (auto i : mp)
{
que.push(i.first);
if (i.second != 2)
{
flag = false;
break;
}
}
if (!flag || que.size() != n)
{
cout << "NO" << endl;
continue;
}
ll sum = 0;
for(int i = n; i >= 1; i--)
{
ll x = que.top();
que.pop();
if(x - sum <= 0 || ((x - sum) % (2 * i)) != 0)
{
flag = false;
break;
}
else
{
sum += (x - sum) / i;
}
}
if (flag)
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
}
}
D - Nezzar and Board
题意
黑板上有 n n n 个不同的整数,可以进行的操作是选取两个数 x , y x,y x,y,将 2 x − y 2x-y 2x−y 放回黑板(不删除选取的数)。问能否经过一系列的操作得出给定的 k k k。
思路
参考:Codeforces Round #698 (Div. 2) D. Nezzar and Board,Codeforces Round #698 (Div. 2) A~F
裴蜀定理:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Np3gOfTy-1612356393165)(C:\Users\29039\AppData\Roaming\Typora\typora-user-images\image-20210201161808476.png)]
把操作看成
x
+
(
x
−
y
)
x + (x - y)
x+(x−y),则整个过程化为元素
x
x
x 加上两个数的差值。又,形如
a
3
−
a
1
a_3 - a_1
a3−a1 的差可以转换为
a
3
−
a
2
+
a
2
−
a
1
a_3 - a_2 + a_2 - a_1
a3−a2+a2−a1,所以任何差
a
n
−
a
m
a_n - a_m
an−am 都能化为
∑
i
=
1
n
−
1
(
a
i
+
1
−
a
i
−
∑
i
=
1
m
−
1
(
a
i
+
1
−
a
i
)
\sum_{i = 1}^{n - 1}(a_{i + 1} - a_i - \sum_{i = 1}^{m - 1}(a_{i + 1} - a_i)
∑i=1n−1(ai+1−ai−∑i=1m−1(ai+1−ai) 的形式,所以我们可以将
2
x
−
y
=
k
2x - y = k
2x−y=k 转化为:
a
1
+
k
1
∗
(
a
2
−
a
1
)
+
k
2
∗
(
a
3
−
a
2
)
+
…
+
k
n
−
1
∗
(
a
n
−
a
n
−
1
)
=
k
a_1 + k_1* (a_2 - a_1) + k_2* (a_3 - a_2) + …+ k_{n - 1}* (a_n - a_{n - 1}) = k
a1+k1∗(a2−a1)+k2∗(a3−a2)+…+kn−1∗(an−an−1)=k
k 1 ∗ ( a 2 − a 1 ) + k 2 ∗ ( a 3 − a 2 ) + … + k n − 1 ∗ ( a n − a n − 1 ) = k − a 1 k_1* (a_2 - a_1) + k_2* (a_3 - a_2) + …+ k_{n - 1}* (a_n - a_{n - 1}) = k - a_1 k1∗(a2−a1)+k2∗(a3−a2)+…+kn−1∗(an−an−1)=k−a1
的形式。
因此,只要存在 a i a_i ai,有其他所有数字的最大公约数等于 k − a i k - a_i k−ai,原式就成立。
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 3e5 + 19;
const ll mod = 1e9 + 7;
ll a[N];
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
ll k;
cin >> n >> k;
ll gcd = 0;
for(int i = 0; i < n; i++)
{
cin >> a[i];
if(i < 1)
continue;
if(i == 1)
{
gcd = a[i] - a[i - 1];
continue;
}
gcd = __gcd(gcd, a[i] - a[i - 1]);
}
bool flag = 0;
for(int i = 0; i < n; i++)
{
if((k - a[i]) % gcd == 0)
{
flag = 1;
break;
}
}
if(flag)
cout << "YES\n";
else
cout << "NO\n";
}
return 0;
}
F - Nezzar and Nice Beatmap
题意
给定 n n n 个点,对其进行重新排列,使之任意连续的三个点形成的角(以中间的点为顶点)小于 90 90 90 度。
思路
参考:Codeforces Round #698 (Div. 2) - Zeronera - 博客园
代码
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define PI acos(-1)
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 1e4 + 19;
const ll mod = 1e9 + 7;
struct node
{
double x;
double y;
node(){}
node(double a, double b){x = a; y = b;}
}a[N];
bool vis[N];
double dis(node a, node b)
{
return sqrt( (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) );
}
int main()
{
int n;
queue<int> ans;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%lf%lf", &a[i].x, &a[i].y);
}
int cnt = 0;
int id = 0;
vis[0] = 1;
do
{
double maxdis = 0;
int num = 0;
ans.push(id + 1);
for(int j = 0; j < n; j++)
{
if(vis[j])
continue;
double tmp = dis(a[id], a[j]);
if(tmp > maxdis)
{
maxdis = tmp;
num = j;
}
}
id = num;
vis[id] = 1;
cnt++;
}
while(cnt < n);
while(!ans.empty())
{
printf("%d", ans.front());
ans.pop();
if(!ans.empty())
printf(" ");
}
printf("\n");
return 0;
}
总结
- B题因为一个特判(大于十倍的d的情况)卡了很久WA了两发,还是太不熟练了;
- 总体感觉蛮怪的,其实觉得发挥的很差,或许是几页的in queue助攻了一下,总之上分上的很不自在
- 虽然每次都说不要死磕前面的题,但是每次都忍不住死磕,,,希望下次能有一丢丢改进
多多包涵,共同进步