Codeforces 919 (div2) a-c题题解
A题 Satisfying Constraints Problem - A - Codeforces
题目概述:一共有3种约束情况。当a = 1时,将k下限约束到x;当a = 2时,将s上限约束到x,当a = 3时;当a = 3时,k将不能等于x;(k和x含义请看题目);
类型:简单模拟;
要点注意:
1.最后在数满足条件的个数cnt时,不能直接正着+1+1(否则会TLE),而是要把先把上下限中间的数通过减法算出来,然后通过-1-1排除掉不合规的点。
2.答案最小值为0,所以输出时有max(cnt,0ll);注意ll;
//
// Created by Mrlaolu on 2024/1/13.
//
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1010;
void solve()
{
int n;
cin >> n;
int min1 = 0;
int max1 = INT_MAX;
vector<int>arr;
for(int i = 0;i < n;++i)
{
int a,t;
cin >> a >> t;
if(a == 1)
{
min1 = max(min1,t);
}
else if(a == 2)
{
max1 = min(max1,t);
}
else if(a == 3)
{
arr.push_back(t);
}
}
int cnt = max1 - min1 + 1;
for(auto it : arr) //-based for 遍历arr
{
if( it >= min1 && it <= max1){cnt--;}
}
cout << max(cnt,0ll) << endl;
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B题 Summation Game Problem - B - Codeforces
题目概述:alice先手在数组中移除k个数据,rob后手在数组中将k个数据乘以-1(变为自己的倒数)。alice希望将操作后数组的总和最大化,rob希望将操作后数组的总和最小化。
类型:博弈题,找规律。
要点注意:
1.因为是alice先手,所以最后总和肯定是要最大化的(相当于我们是alice),而在alice处理后rob也要想方设法让alice处理后的数组总和最小。
2.通过观察可以发现,alice如果要移除数据也是要移除数组里最大的那几个(因为rob只要拿了当前数组中最大的那个就能让总和最小化,换句话说,拿rob对他最有利),所以可以用sort()对数组进行排序,然后进行从大到小进行移除,每次移除都算总和,最后通过查找出最大的总和来作为答案。
3.在从大到小进行移除并算总和时,注意不能正向一个个加过来(会变成O(N^2)爆时间复杂度),而是要倒着维护总和sum(详情看代码)。
//
// Created by Mrlaolu on 2024/1/13.
//
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1010;
void solve()
{
int n,k,x;
cin >> n >> k >> x;
vector<int>a(n);
int sum = 0;
int seg = 0;
for(int i = 0; i < n; ++i)
{
cin >> a[i];
sum += a[i];
}
sort(a.begin(),a.end(),greater<int>());
for(int i = 0;i < x;++i)
{
seg += a[i];
}
int sumr = 0;
vector<int>arr(k + 1);
for(int i = 0;i <= k;++i) //维护sum部分 这样子时间复杂度是O(n^2)
{
arr[i] = sum - 2 * seg - sumr;
seg -= a[i];
sumr += a[i];
if(i + x < n){seg += a[i + x];}
}
int ans = -1e9;
for(int i = 0;i < k + 1;++i)
{
ans = max(ans,arr[i]);
}
cout << ans << endl;
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C题 Partitioning the Array Problem - C - Codeforces
题目概述:穷举出所有k使得k能被n整除,并将数组平均切成n / k份(每份长度为k),如果存在一个m(m >= 2)使得将所有数的每个数都变为自身模m( a i a_i ai = a i a_i ai % m)后,各份数组相互全等(完全),则k可行。求有多少个可行的k。
类型:暴力,数论。
注意要点:
1.最重要的点就在于如何判断有没有m使这个k成立,而不是获取这个准确的m。而这个m成立的关键就在于——在每份数组中相对位置相同的数据余数相同(也就是说 a i − m ∗ b = = a i + k − m ∗ c a_i - m * b == a_{i+k} - m * c ai−m∗b==ai+k−m∗c ,其中b,c为随机一个符合条件的值)。所以,我们可以通过将在每份数组中处于相同的相对位置的数据进行做差,并通过求gcd,如果gcd(最大公约数)不为1,则说明这个最大公约数就是m,则这个k可行。
//
// Created by Mrlaolu on 2024/1/13.
//
#include<iostream>
#include "vector"
#include "map"
#include "algorithm"
#define int long long
#define endl '\n'
using namespace std;
const int N = 1010;
void solve()
{
int n;
cin >> n;
vector<int>a(n);
for (int i = 0; i < n; ++i)
cin >> a[i];
vector<int>div;
int cnt = 0;
for (int i = 1; i < n; ++i)
{
if (!(n % i)) { div.push_back(i); }
}
for (int i = 0; i < div.size(); ++i)
{
vector<int>dif;
int g = -1;
for (int p = 0; p + div[i] < n; ++p)
{
int temp = abs(a[p] - a[p + div[i]]);
if (!temp) { continue; }
dif.push_back(temp);
if(g == -1){g = temp;}
else {g = __gcd(g,temp);}
}
if (g != 1) { cnt++; }
}
cout << cnt + 1 << endl;
}
signed main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
cin >> t;
while (t--) {
solve();
}
return 0;
}