Codeforces Round #797 (Div. 3) A-G
Codeforces Round #797 (Div. 3) A-F
https://codeforces.com/contest/1690
A. Print a Pedestal (Codeforces logo?)
就是一个codeforces(颁奖台)的形状;中间的 最高,左边第二,右边第三
然后要使得中间的尽可能小,那么就按照等差数列来构造处理。
最理想情况下是 \(x-1, x, x-2\),且满足\(3x-3=n\),即\(x=\frac{n+3}{3}\)
然而会有些许偏差,所以我们根据样例作出适当调整,即x向上取整,然后按照\(x-1,x,n-x-x+1\)且\(x=\frac{n+3+2}{3}\)来构造
注意每一项都要>0,所以特判一下右边为0的时候,要把左边挪一个过来
over
总之就是注意一些小细节
Code:
#include <bits/stdc++.h>
using namespace std;
void solve () {
int n;
cin >> n;
int x = (n+3+2) / 3;
int a = x-1, c=n-x-x+1;
if (c == 0)
a--, c++;
cout << a << ' ' << x << ' ' << c << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
B. Array Decrements
题意:每次可以把数列a中所有大于0的项减1,问能否通过若干次操作使得a的每一项都等于b
思路:如果对应项b是0的话,那么该点处a的可减上限是\(\infty\)(因为减到0之后就不对他进行操作了,我们可以称这样的点为无下限点)
所以能做的就是统计有下限(也就是\(b_i\neq 0\)处\(a_i\)所需改变的最大值\(dx\),如果出现 有下限点所需操作 不等于\(dx\)的情况,那么必定是不可能的。他已经达到要求了,别的数列还要减)
呃我语言表达能力不太行,可以看看代码,会好懂很多
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 5e4 + 5;
int a[N], b[N], n;
void test () {
for (int i = 1; i <= n; i ++)
cout << a[i] << ' ';
cout << "\n";
}
void solve () {
bool suc = true;
cin >> n;
for (int i = 1; i<= n; i ++)
cin >> a[i];
int dx = -1; //统计最少要减多少个
for (int i = 1; i <= n; i ++) {
cin>> b[i], a[i] -= b[i];
if (a[i] >= 0) dx = max (dx, a[i]); //注意可以取等
if (a[i] < 0)
suc = false;
}
if (!suc) {
cout << "NO\n";
return ;
}
//test ();
for (int i = 1; i <= n; i ++) {
//cout << dx << ' ';
//如果b[i]是0的话就可以无限减,如果不是则不行
if (b[i]) {
if (dx != a[i]) {
cout << "NO\n";
return ;
}
}
}
cout << "YES\n";
}
int main () {
IOS;
int t;
cin >> t;
while (t --) {
solve ();
}
}
//ai<bi 肯定不行
//差值必须要相等(减到0的可以不等)
//复盘一下,要小心一些细节
C. Restoring the Duration of Tasks
简单模拟题。
题意:有若干个任务,每个任务都有计划起始时间\(a_i\)和计划完成时间\(b_i\),而在实际处理的过程中,如果当前任务还没有处理完,就会先把当前的做完再接着去做下一个(任务终止点不变,但是如果有前面的任务覆盖了的话,就从最近的上一个任务的结束点开始算)
思路:所以就按顺序遍历右端点,然后找到距离右端点最近的上一个结束点,如果找到的点在该段之外(没有重叠)就直接按完整区间算,否则用找到的右端点当作新起始点
似乎又说复杂了。。看代码就能懂的:
#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef pair<int, int> pii;
const int N = 2e5 + 5;
int a[N], b[N];
// struct Node {
// int idx, l, r;
// bool
// }a[N];
void solve () {
int n;
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
for (int i = 1; i <= n; i ++)
cin >> b[i];
cout << b[1] - a[1] << ' ';
for (int i = 2; i <= n; i ++) {
bool find = false;
for (int j = i - 1; j >= 1; j --) {
// if (b[j] <= a[i])
// break;
if (b[j] > a[i]) {
find = true;
cout << b[i] - b[j] << ' ';
break;
}
}
if (!find)
cout << b[i] - a[i] << ' ';
}
cout << endl;
}
signed main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//出现区间重叠:
//右端点不动,左端点变为距离右端点最近的上一个右端点(且一定要在左边)
D. Black and White Stripe
题意:给定一个字符串s,问要把多少个W变成B,才会有k个连续的B
思路:利用前缀和,统计每一段内的含'W'量,然后扫s中每一段长度为k的段,记录其中含'W'量的最小值,就是答案!
很巧妙的思路啊,我要积累一下(记小本本)
注意不用每次都更新cnt[],防止超时
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int cnt[N]; //记录B的个数
void solve () {
int n, k;
string s, t;
cin >> n >> k >> s;
s = ' ' + s;
for (int i = 1; i <= n; i ++)
cnt[i] = cnt[i - 1] + (s[i] == 'W'); //cnt[0]一直是0,所以不需要memset
int ans = 0x7fffffff;
for (int i = k; i <= n; i ++)
ans = min (ans, cnt[i] - cnt[i - k]);
cout << ans << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//要把多少个W变成B,才会有k个连续的B
//首先已经有了长度>=k的段了,那么就直接0
//用最长的往两边拓展
//前缀和
E. Price Maximization
题意:给出数列\(a_n\),任意两两\(a_i,a_j\)组成一组,使得所有\(\frac{a_i+a_j}{k}\)之和最小
思路:首先统计每一个数中的含k量,然后记录每一个余数,两两组合拼在一起,再看能凑出多少个k
具体操作:排序 + 双指针两头扫
!!要开long long
#include <bits/stdc++.h>
#define int long long //传统美德不能忘啊
#define endl "\n"
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
const int N = 2e5 + 5;
void solve () {
int n, k, ans = 0;
cin >> n >> k;
vector <int> v;
for (int i = 1; i <= n; i ++) {
int x;
cin >> x;
ans += x / k;
if (x % k)
v.push_back (x % k);
}
//cout << ans << endl;
if (v.empty ()) {
cout << ans << endl;
return ;
}
sort (v.begin (), v.end ());
n = v.size ();
for (int i = 0, j = n - 1; i < j; ) {
if (v[i] + v[j] >= k)
ans += (v[i] + v[j]) / k, i ++, j --; //这里写成ans++, i++, j++ 也没问题的
else
i ++; //凑不出,j不动,i往后挪肯定是最优的,因为按照升序排列
}
cout << ans << endl;
// for (auto i : v)
// cout << i << ' ';
// cout << endl;
}
signed main () {
IOS;
int t;
cin >> t;
while (t --) {
solve ();
}
}
//看余数能凑出多少个k即可
F. Shifting String
题意:字符串s按照p[i]的规则进行重新排列,问至少要操作该过程多少次,才能恢复原串
把变换后的串构造出来,然后找循环节,求LCM
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
using namespace std;
void solve () {
int n;
string s;
cin >> n >> s;
vector <int> p(n + 1);
vector <bool> vis(n + 1);
for (int i = 1; i <= n; i ++)
cin >> p[i];
s = ' ' + s;
int ans = 1;
for (int i = 1; i <= n; i ++) {
if (vis[i]) continue;
string t; //匹配
for (int j = i; !vis[j]; j = p[j])
vis[j] = true, t += s[j]; //构造变换后的串
int m = t.size ();
for (int i = 1; i <= m; i ++) {
if (m % i) continue;
bool suc = true;
for (int j = 0; j < m && suc; j ++) {
if (t[j] != t[(j + i) % m])
suc = false; //并非循环节
}
if (suc) {
ans = lcm (ans, i);
break;
}
}
}
cout << ans << endl;
}
signed main () {
IOS;
int t;
cin >> t;
while (t --) {
solve ();
}
}
//置换群+s
//求每个环回到最初状态所需步数的lcm
G. Count the Trains
题意:给定序列an,满足对于所有\(i\geq1\),有\(a_{i-1}>= a_i\)。然后有操作,\(a_k=a_k-d\),要满足该操作之后,序列仍满足要求。(在每次操作过后,如果后一项比前一项大的话,就让他等于前一项)求每次操作过后,数列中不相等的数的个数。
思路:统计\(differ\),然后又有重复的要考虑,所以很容易想到map来维护。在每次更新之后都要"前瞻后顾",即 找的到前面有比它小的,就把找到的这个删掉;然后看后面,把比它大的删掉。
(前面只删一个,后面一直删)
\(Code reference: jls\)
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
#define IOS ios::sync_with_stdio (0);cin.tie(0);cout.tie (0);
using namespace std;
const int N = 1e5 + 5;
int a[N];
int n, m;
map<int, int> mp;
void add (int x, int ax) {
mp[x] = ax;
auto it = mp.find (x);
if (it != mp.begin () && ax >= prev(it)->second) //相等的也要移除
mp.erase (it);
else {
while (next(it) != mp.end () && ax <= next (it)->second)
mp.erase (next(it));
}
}
void solve () {
mp.clear ();
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
add (i, a[i]);
}
while (m --) {
int idx, k;
cin >> idx >> k;
a[idx] -= k;
add (idx, a[idx]);
cout << mp.size () << ' ';
}
cout << endl;
}
signed main () {
IOS;
int t; cin >> t;
while (t --) {
solve ();
}
}
看到这个绿绿的就是心情舒畅!