之前开的一场虚拟赛,鸽了好久,今天找了个时间把题解写了
给个传送门
A. Add Odd or Subtract Even
题意:给你两个数a,b 你可以在给a加上一个奇数或者减去一个偶数使a变成b,问你最少需要操作几次。
很简单,a==b不需要操作,a>b 如何a-b 是奇数,那么加上个奇数就行,如果是偶数,那么加上一个大一点的奇数再减1就行,同理a<b。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int main (){
int n;
cin>>n;
while(n--){
int a,b;
cin>>a>>b;
if(a==b){
cout<<0<<endl;
}
else if(a<b){
if((b-a)%2==1)cout<<1<<endl;
else cout<<2<<endl;
}
else if(a>b){
if((a-b)%2==1)cout<<2<<endl;
else cout<<1<<endl;
}
}
return 0;
}
B.WeirdSort
题意: 给你一个数组,然后告诉你哪些地方可以进行操作,操作是和它后面的那个数进行交换,最后问你能否交换出一个不下降的序列。
最开始的想法是,任意一个比相邻的数的后面那个大的话就必须要能操作,发现wa了,才明白是想法不对。好在及时改正,我的思路是,某个数要想变成不下降的顺序,那么如果他前面有一个数比他大,那么这两个数之间必须都要能进行交换操作。具体看代码。
#include <bits/stdc++.h>
using namespace std;
const int N=105;
int a[N],p[N];
int main (){
int t;
cin>>t;
while(t--){
int n,m,x;
cin>>n>>m;
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=0;i<m;i++)cin>>x,p[x]=1;
int flag=0;
for(int i=1;i<=n;i++){
int ans=100;
for(int j=1;j<i;j++){
if(a[j]>a[i]){
ans=j;
break;
}
}
for(int j=ans;j<i;j++){
if(p[j]!=1){
cout<<"NO"<<endl;
flag=1;
break;
}
}
if(flag==1)break;
}
if(flag==0)
cout<<"YES"<<endl;
}
return 0;
}
c.Perform the Combo
题意: 举个例子说吧。你在玩一个字符串敲击游戏。比如你现在要敲abca ,但是告诉你你会在敲第3下的地方失败,那么你就要重新敲,这样你就敲了abc,abca一共7下,告诉你一系列会失败的地方,问你最后26个字母分别敲了几下。
这题其实挺有意思的,数据
2
∗
1
0
5
2*10^5
2∗105 暴力的话
O
(
n
2
)
O(n^2)
O(n2) 的复杂度肯定会爆。网上以及官方题解都是使用前缀和做的。比赛的时候这题做了挺久,好在后面A了,我的算法不太一样。简单讲讲怎做吧。
比放说我们要求codeforces这么一个字符串。
出错的地方分别是2 8 3 2 9
那么我们就要统计这么一些子串
co codeforc cod co codeforce
怎么做呢,先将他们按长度排序
co
co
cod
codeforc
codeforce
为什么要竖着写呢?这样从左往右统计字符串的时候就有规律可言,比如说第一个字符c,它在每个字符串里都出现过,所以我们直接先加5,o也是,d的时候前两个字符串就没了,所以加
5
−
2
5-2
5−2 ,为什么是
5
−
2
5-2
5−2呢,第三个字符串出现的起始位置是第3个到最后,前面两个没有了。具体可以看代码。
#include <bits/stdc++.h>
using namespace std;
const int N=2e5+5;
char ch[N];
int p[N];
int a[30];
int main (){
int t;
cin>>t;
while(t--){
memset(a,0,sizeof(a));
int n,m;
scanf("%d%d",&n,&m);
cin>>ch;
for(int i=0;i<m;i++){
cin>>p[i];
}
sort(p,p+m);
int x=0;
for(int i=0;i<n;i++){
while(i>(p[x]-1)){
if(x==m) break;
x++;
}
a[ch[i]-'a']+=(m-x+1);
}
for(int i=0;i<26;i++){
printf("%d ",a[i]);
}
puts("");
}
return 0;
}
D - Three Integers
题意: 给你
a
<
=
b
<
=
c
a<=b<=c
a<=b<=c三个数,你可以对他们呢进行加1减1的操作,问你最少一共操作多少次使得
c
c
c可以整除
b
b
b,
b
b
b 可以整除
a
a
a .
思路其实就是暴力,但是有一定的技巧。比如说枚举a的时候只需要从
1
−
2
∗
a
1-2*a
1−2∗a 即可,因为问的是最少次数,如果你超过
2
∗
a
2*a
2∗a,你不如直接变成1。 枚举b的时候道理是一样的,可以可以只枚举a的倍数,每次都加a。因为要求的是最少次数,所以最后求c的时候,
c
=
⌊
c
/
b
⌋
∗
b
c=\lfloor c/b \rfloor *b
c=⌊c/b⌋∗b 或者是
c
=
⌈
c
/
b
⌉
∗
b
c=\lceil c/b \rceil *b
c=⌈c/b⌉∗b
这样可以保证次数一定是最小的。
#include <bits/stdc++.h>
using namespace std;
int A,B,C,ans,cnt;
int main(){
int n;
cin>>n;
while(n--){
int a,b,c;
cin>>a>>b>>c;
ans=1e9,cnt=0;
for(int i=1;i<=2*a;i++){
for(int j=i;j<=2*b;j+=i){
int c1=(c/j)*j;
int c2=(c/j+1)*j;
if(c1>=j){
cnt=abs(i-a)+abs(j-b)+abs(c-c1);
if(ans>cnt){
ans=cnt;
A=i;
B=j;
C=c1;
}
}
if(c2>=j){
cnt=abs(i-a)+abs(j-b)+abs(c-c2);
if(ans>cnt){
ans=cnt;
A=i;
B=j;
C=c2;
}
}
}
}
cout<<ans<<endl<<A<<" "<<B<<" "<<C<<" "<<endl;
}
return 0;
}