Codeforces Round #787 (div 3) A~E
比赛题目链接
https://codeforces.com/contest/1675
A.Food for Animals(模拟)
题意
有a份狗粮,b份猫粮,c份万能粮,问是否能够满足所有x条狗和y只猫
分析
先检视x条的狗能不能把a份狗粮吃掉,若吃完了狗粮,就再去吃c份通用的,一旦通用变为负数,表示的无法满足;猫粮也是同理
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while(t --)
{
int a,b,c,x,y;
cin >> a >> b >> c >> x >> y;
if(a >= x) ;
else c -= x - a;
if(c < 0 )
{
cout << "NO" << endl;
continue;
}
if(b + c >= y) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
B.Make It Increasing(暴力)
题意
一个数组,可以对其中任意一个数除2并向下取整,经过多少次操作,可以将数组变为严格递增序列(升序并且每个数字都不相等)。
分析
数组大小只有30,数据大小1e9也不会超过2^{30},暴力即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n;
int main()
{
int T; cin >> T;
while (T --)
{
cin >> n;
for (int i = 1; i <= n; i ++)
cin >> a[i];
//cnt用来存储次数,flag用于标记是否可以实现
int cnt = 0;
int flag = 0;
for (int i = n - 1; i >= 1; i --)
{
if (a[i] < a[i + 1])
continue;
while (a[i] >= a[i + 1])
{
a[i] /= 2;
cnt ++;
//如果除得不能再除了还是避免不了相等,那就标记一下
if (a[i] == 0 && a[i] >= a[i + 1])
{
flag = 1;
break;
}
}
}
//如果被标记,说明不符合题意,输出-1
if (flag) puts ("-1");
else cout << cnt << "\n";
}
return 0;
}
C. Detective Task(模拟 + 思维)
题意
一个字符串,包含0,1,?。判断几个人有嫌疑,0代表不在,1代表在,?代表不记得。除了小偷每个人必须说真话。
分析
一共4种情况,
有0有1:第一个0之前的1到0之间都有嫌疑;
有1没0:最后一个1后面的都有嫌疑;
没1有0:第一个0之前的都有嫌疑;
没1没0:每个人都有嫌疑。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin >> t;
while (t--)
{
string s;
cin >> s;
//ans用来存储犯人数量,idx表示离现在遍历的位置最近的1的下标
int ans = 0, idx = -1;
for (int i = 0; i < s.size(); i++)
{
if (s[i] == '1')
{
idx = i;
}
else if (s[i] == '0')
{
//有1有0,中间的全部都是犯人
if (idx != -1)
{
ans = i - idx + 1;
}
//有0没1,第一个0之前的都有嫌疑;
else ans = i + 1;
break;
}
}
//重点:ans = 0并不意味着没有犯人,还有无1无0的情况
if (ans == 0)
{
//无1无0,全是犯人
if (idx == -1)
{
ans = s.size();
}
else ans = s.size() - idx;
}
cout << ans << endl;
}
return 0;
}
D.Vertical Paths(dfs + 链表)
题意
一棵树,将这棵树拆成一条一条链,最少能拆成多少条,并输出每条长度和每条点。
分析
一个破题想一天,不过难写是真的难写;
可以用链表来存以某个数为头结点的数,当某个数的头结点为他本身的时候我们把他设为根结点,用一个vector数组来存他的路径数组,用一个len来记录路径数组的长度,用st数组来记录每个点的状态;
从根结点开始搜,当搜的这个点的指针指向-1时说明他是这条路的最后一个数,所以路径条数++;
当不等于-1时,我们遍历以这个点为头结点的链表,当遍历到的点没有被搜过的时候就把他加入路径数组中,并改变他的状态,然后搜这个点。最后输出路径条数和每个路径数组中存的点即可。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int n;
const int N = 200005;
//链表三巨头
int h[N];
int e[N];
int ne[N];
// 当前每个点的状态
int st[N];
//当前链表指针 ,路径数组长度,
int idx, len, root;
vector<int> ans[N];
void into_it()
{
memset(h, -1, sizeof h);
memset(st, 0, sizeof st);
for (int i = 1; i <= n; i++)
{
ans[i].clear();
}
idx = 0;
//答案序列的长度
len = 1;
//根结点,当父节点等于自己的时候赋值给root
root = -1;
}
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
void dfs(int u)
{
//说明一条路遍历完了,路的条数++,返回
if (h[u] == -1)
{
len++;
return;
}
for (int i = h[u]; i != -1; i = ne[i])
{
int j = e[i];
//当没有走过的时候
if (st[j] == 0)
{
ans[len].push_back(j);
st[j] = 1;
dfs(j);
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n;
//初始化,清空上次查询残留
into_it();
for (int i = 1; i <= n; i++)
{
int num;
cin >> num;
//当父节点等于本身的时候说明是根结点
if (num == i)
{
root = num;
}
//否则就把i加入以num为头的链表中
else
{
add(num, i);
}
}
ans[len].push_back(root);
st[root] = 1;
dfs(root);
len--;
//输出路径条数
cout << len << endl;
for (int i = 1; i <= len; i++)
{
//输出每条路径的长度
int q = ans[i].size();
cout << q << endl;
//输出每条路径中存的点
for (int j = 0; j < q; j++)
{
printf("%d ", ans[i][j]);
}
printf("\n");
}
}
return 0;
}
E.Replace With the Previous, Minimize(贪心)
题意
一个字符串,每次操作可以使一个字母循环替换成该字母的前一个(如c->b),消耗一个次数,但是其他字母再次替换到此处时无需额外扣取次数(如前面c->b后,后面的d->c->b时,只用扣取d->c的一个费用),在最多m次操作之后,求出字典序最小的字符串。
分析
如果一个字母x足够大,当它下降时,比它小的字母全部都可以下降到同样的位置;而不会被一起调整的字母要不就是过大,要不就是比调整后的字母小;但是如果一个字母x太大并且在x - k的范围内字母较少,那就直接舍弃掉,从比x小一点点的开始找;
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
char s[N];
int main()
{
int T;
cin >> T;
while (T--)
{
int n, k;
cin >> n >> k;
cin >> s;
int maxm = 0;//一定要定义一个除了被大于k数字影响的最大下降数
for (int i = 0; i < n; i++)
{
if (s[i] - 'a' > k)//如果下降k次到不了a
{
k = k - maxm;
char max_line = s[i];//把当前最大值更新为该数
char min_line = s[i] - k;//该数能下降的最小字母
for (int j = 0; j < n; j++)
if (s[j] >= min_line && s[j] <= max_line) //在下降区间内的
s[j] = min_line;//全部变成该数变化后的字母;
break;
}
maxm = max(maxm, s[i] - 'a');//如果不超过k,更新最大下降数
}
for (int i = 0; i < n; i++)
if (s[i] <= 'a' + maxm)
{
//不是加k,因为当前所有到不了a的字母都已经被更新到最优解,这一项只是为了能到a的数全部变成a
s[i] = 'a';
}
cout << s << endl;
}
}

浙公网安备 33010602011771号