Codeforces Round #787 (Div. 3)
E. Replace With the Previous, Minimize
题意:
给定一个字符串s,你可以进行一下操作k次:
将s中所有字符变成前一个字符,例如可以所有
c
变成b
、将所有a
变成z
。求:
k次操作后所得到的的字符串按字典序最小
题目要求按字典序最小,那我们就尽可能的把前面的字符变到最小:
情况1:
如果k>=25则所有字母都可以变成字符
a
(k的数据1e9就是唬人的)
情况2:
如果k次操作全部放在第一个字符,且操作完后第一个字符还不能是
a
则将s中所有小于等于s[0]且大于s[0]-k的字符变成s[0]-k,否则原样输出。(此处用的是
ascll
)
情况3:
如果k次操作内,第一个字符已经变成
a
,则去从前往后找到第一个k
次操作不能变成a
的字符t
,然后记录字符t
与a
的ascll
值,由于字符t
前面已经操作了n次(n为这个字符t
前所有可以变成a
字符的操作数的最大值),那么这个字符最终只能变成char(t+(k-n))
。例如样例中
4 19 ekyv
第三个字符y不能变成
a
,但是前面将e
、k
变成a
后,已经用了max('e','k')-'a'
=10
次,所以y
只能变成y-(19-10)
=p
故答案为:
aapp
完整代码:
#include<bits/stdc++.h>
using namespace std;
int a[200007];
void solve(){
int n,k;
cin >>n>>k;
char s[n];
getchar();
for(int i=0;i<n;i++){
scanf("%1c",&s[i]);
}
int num_c=0;
if(k>=25){
for(int i=1;i<=n;i++){
cout <<'a';
}printf("\n");
return;
}
if(s[0]-'a'>k){
cout <<char(s[0]-k);
for(int i=1;i<n;i++){
if(s[i]<=s[0]&&s[i]>s[0]-k){
cout <<char(s[0]-k);
}else{
cout <<char(s[i]);
}
}
printf("\n");
return;
}
for(int i=0;i<n;i++){
a[i+1]=s[i]-'a';
}
int num_p=0;
char c;
for(int i=1;i<=n;i++){
if(a[i]<=k){
num_c=max(a[i],num_c);
}else{
num_p=a[i];
c = 'a'+a[i]-(k-num_c);
break;
}
}
for(int i=1;i<=n;i++){
if(a[i]<=num_c){
printf("a");
}else{
if(a[i]<=num_p&&a[i]>=num_p-(k-num_c)){
printf("%c",c);
}else{
printf("%c",s[i-1]);
}
}
}
printf("\n");
}
int main(){
int T;
cin >>T;
while(T--){
solve();
}
return 0;
}
A. Food for Animals
题意:
输入五个整数
a
b
c
d
e
a
代表现有狗粮的数量
b
代表现有猫粮的数量
c
代表现有通用粮的数量
d
代表狗的数量
e
代表猫的数量求:
是否能满足每只猫、狗都分到一包粮。
签到题,数据在int
范围。
核心代码:
int a, b, c, x, y;
std::cin >> a >> b >> c >> x >> y;
if (a + c >= x && b + c >= y && a + b + c >= x + y) {
cout << "YES\n";
} else {
cout << "NO\n";
}
B. Make It Increasing
题意:
给
n
个整数构成一个整数序列,你可以进行一下操作若干次:将一个数除以2(向下舍入)
求:
是否若干次操作后得到一个严格升序的序列,若可以则输出操作的次数,若不能则输出
-1
题意很简单,整数个数不超过2e5。
我们直接从整数序列末尾向前进行操作
完整代码:
#include<bits/stdc++.h>
using namespace std;
int a[200007];
void solve(){
int n;
cin >>n;
//读入n个整数
for(int i=1;i<=n;i++){
cin >>a[i];
}
long long ans = 0;
for(int i=n-1;i>=1;i--){
while(a[i+1]<=a[i])//找到满足条件的a[i]
{
if(a[i]==0)//不满足严格升序
{
cout <<-1<<endl;
return;
}
a[i]/=2;
ans++;
}
}
cout <<ans<<endl;
}
int main(){
int T;
cin >>T;
while(T--){
solve();
}
return 0;
}
C. Detective Task
题意:
有
n
个人依次参观一幅画,参观完后发现画丢了。小偷在这群人之中。询问这些人进入房间时画是否还在,他们会回答:
- 0(画没了)
- 1(画还在)
- ?(俺也不知道)
小偷可以回答任意答案(牛马一个,盗窃犯法,切勿模仿)而其他人只会回答真话,或者不知道(起码不是表面朋友)。
求:
可以盗窃这幅画的人数
我们由样例简单分析一下
当人数为
一
时,肯定就是他是小偷(无论他说了什么)!ans=1;
1234567
(这是下标)
1110000
(这是样例)
此时小偷可能是第
3
个人是小偷(说了谎),第4
个人说真话。或者第
3
个人说真话,第4
个人是小偷(也说了真话,牛蛙)。ans=2;
?????
- 此时
五
个人都可能偷画。ans=5;
12345678
(这是下标)
1?1??0?0
(这是样例)
- 假设第
7
个人是小偷,则说明第6
个人说了真话,说明画已经丢了,则假设不成立。- 假设第
2
个人或第一个人是小偷,第3
个人参观时画还在,相悖,假设不成立。则第
3
4
5
6
个人可能是偷画的人ans=4;
0?0???
- 第一个人肯定是小偷,否则画一定在(朋友说真话)
- ans=1
??11
- 如果第三个人是小偷,则第四个人说的是0
则一定是第
4
个人ans=1;
??0??
- 若第三个人不是小偷,前两个之一必定是小偷
- 若第三个人是小偷,则后两个肯定是朋友
ans=3;
由上述分析不难看出来
- 遇到0时,小偷一定在这个人之前或者是就是这个人。
- 遇到?时,小偷可能会是他(如果前面没有0)
- 遇到1时,则这个人之前的?全部不是小偷,且这个人可能是小偷(说谎)
完整代码:
#include<bits/stdc++.h>
using namespace std;
void solve(){
string s;
cin >>s;
bool p = false;
int ans = 0;
if(s.length()==1){//如果只有一个人,那么小偷必定是他
cout <<1<<endl;
return;
}
int ans_w=0,ans_1=0;//问号的数量和1的数量
for(int i=0;i<s.length();i++){
if(s[i]=='0'){
if(s[i-1]=='1'||s[i-1]=='?'||i==0){
cout <<1+ans_w+ans_1<<endl;
return;
}
}else if(s[i]=='?'){
ans_w++;
}else if(s[i]=='1'){
ans_w=0;
if(s[i-1]!='1') ans_1=1;
}
if(i==s.length()-1){
cout <<ans_w+ans_1<<endl;
}
}
}
int main(){
int T;
cin >>T;
while(T--){
solve();
}
return 0;
}