Codeforces Round #787 (Div. 3)
A. Food for Animals
- 比较简单的小题写判断条件时细心一点即可
code
#include<bits/stdc++.h>
using namespace std;
int n, m, k, t;
int main()
{
cin >> t;
while(t --)
{
int a, b, c, x, y;
cin >>a >> b >> c >> x >> y;
if(x <= a && y <= b) puts("YES");
else if(y <= b && x <= a + c) puts("YES");
else if(y <= c + b && x <= a) puts("YES");
else if(a < x && b < y)
{
if(c >= (x - a) + (y - b)) puts("YES");
else puts("NO");
}
else puts("NO");
}
return 0;
}
B. Make It Increasing
- 贪心,从后往前变化即可
- 若某项在除2的过程中变为0且不为第一个位置,则不合法
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, inf = 2e9 + 10;
int n, m, t;
int a[N];
int main()
{
cin >> t;
while(t --)
{
int cnt = 0, flg = 0;
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
a[n] = inf;
for(int i = n - 1; i >= 0; i --)
{
while(a[i] >= a[i + 1] && a[i] >= i)
{
a[i] /= 2;
cnt ++;
}
if(a[i] < i)
{
flg = 1;
break;
}
}
if(flg) puts("-1");
else cout << cnt << "\n";
}
return 0;
}
C. Detective Task
- 因为只有小偷可以说真话,则关键思考部分在最后一个0和第一个1
- 要么二人之一在说谎
- 要么两人之间的人在说谎
- 最后一个1要么它右边的是小偷,要么就是他在说谎
- 第一个0要么它左边的是小偷,,要么就是他在说谎
- 全是
?
自然全部都有嫌疑
code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, inf = 2e9 + 10;
int n, m, t;
int a[N];
int main()
{
cin >> t;
while(t --)
{
string s;
cin >> s;
int len = s.size();
int r1 = 0, r2 = len - 1;
int flg = 0;
int u;
for(int i = 0; i < len; i ++)
if(s[i] == '1') r1 = i;
for(int i = 0; i < len; i ++)
if(s[i] == '0')
{
r2 = i;
break;
}
if(r2 < r1) puts("1");
else cout << r2 - r1 + 1 << "\n";
}
return 0;
}
D. Vertical Paths
-
题目大意为一棵树上的路径数,很容易发现路径数等于叶子节点数
-
我们可以开一个布尔数组判断该点是否已经在路径某个中
-
从叶子节点向上找路是一个不错的方法,可以开一个动态数组边找边储存
code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, k, t;
int f[N], le[N];
bool st[N];
vector<int> p, q;
void _clear()
{
memset(le, 0, sizeof le);
memset(st, 0, sizeof st);
memset(f, 0, sizeof f);
}
int main()
{
cin >> t;
while(t --)
{
_clear();
int root;
cin >> n;
for(int i = 1; i <= n; i ++)
{
cin >> f[i];
if(f[i] == i) root = i;
else le[f[i]] ++;;
}
int cnt = 0;
for(int i = 1; i <= n; i ++)
if(!le[i]) cnt ++;
cout << cnt << "\n";
for(int i = 1; i <= n; i ++)
{
p.clear();
if(!le[i])
{
int u = i;
while(st[u] == 0)
{
p.push_back(u);
st[u] = true;
u = f[u];
}
cout << p.size() << "\n";
for(int i = p.size() - 1; i >= 0; i --) cout << p[i]<< " ";
puts(" ");
}
}
puts("");
}
return 0;
}
E. Replace With the Previous, Minimize
-
题目大意
- 定义了一种操作:选择字符串中的一个字符,把字符串中所有的该字符换成该字母字母序上的前一个字母
- 求通过有限操作次数内能得到的最小字符串
-
基于字典序的特性,我们理想状态下是越靠前的字母越小越好
-
所以我们从第一个字母开始操作,并记录下操作的字母是什么,如果后边出现同样的字母直接转化即可
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
int n, m, t, k;
bool st[N];
int main()
{
cin >> t;
while(t --)
{
memset(st, 0, sizeof st);
string s;
cin >> n >> k >> s;
for(int i = 0; i < n; i ++)
{
int u = s[i] - 'a';
while(k && u )
{
if(!st[u] && k )
{
st[u] = 1;
k --;
}
u --;
}
}
for(int i = 0; i < n; i ++)
{
int u = s[i] - 'a';
while(u && st[u]) u --;
s[i] = 'a' + u;
}
cout << s << "\n";
}
return 0;
}
慢慢分析,不要害怕