前言
关于菜狗博主经常托更曾经说要日更结果已经陷入月更的状态让人恨不得想拿把西瓜刀交流一下结果踩到狗屎运系统两次发人机粉导致已经百粉的狗血现实。
A - Linear Keyboard(map)
比赛链接:https://codeforces.com/contest/1607/problem/A
题目大意
现在给你一个字符串a,字符串a包含 26 26 26个英文字母,代表了一个特殊的键盘。
再给定一个字符串 s s s,请求出 s [ i ] s[i] s[i]在这个特殊的键盘上与 s [ i − 1 ] s[i-1] s[i−1]之间的距离的总和。
例如,字符串a为abcdefghijklmnopqrstuvwxyz
,字符串s为hell
,则距离总和为 ∣ 5 − 8 ∣ + ∣ 12 − 5 ∣ + ∣ 12 − 12 ∣ = = 10 |5-8|+|12-5|+|12-12|==10 ∣5−8∣+∣12−5∣+∣12−12∣==10。
思路
用 m a p map map记下每一个英文字母的位置即可。
(用string.find也是可以做的,方法太多)
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
map<char,int> mp;
string s1,s2;
cin>>s1;
cin>>s2;
int ans=0;
for(int i=0;i<26;i++)
mp[s1[i]]=i;
for(int i=1;i<s2.size();i++)
ans+=abs(mp[s2[i]]-mp[s2[i-1]]);
cout<<ans<<endl;
}
}
B - Odd Grasshopper(数学+思维)
比赛链接:https://codeforces.com/contest/1607/problem/B
题目大意
现在x轴上有一只蝗虫(令和老大哥——u咩社长 )。
蝗虫每一秒都会进行一次跳跃。
如果蝗虫的当前位置为奇数,它就会向x轴的负方向
跳跃;否则就会向x轴的正方向
跳跃。蝗虫跳跃的距离取决于这是第几次起跳。若当前为第i次起跳,那么蝗虫此次跳跃的距离为i。
求出蝗虫在初始位置为 x x x的情况下跳跃 n n n次之后所处的位置。
思路
非常有趣的题。
首先要先复习一下小学数学知识:
1.奇数+奇数==偶数
2.奇数+偶数==奇数
3.偶数+偶数==偶数
4.奇数-偶数==奇数
5.奇数-奇数==奇数
6.偶数-偶数==偶数
7.偶数-奇数==奇数
我们假设当前的位置为pos
,pos
的初始值为 x x x。
接下来我们来处理初始 x x x的两种不同情况:
起跳位置x为偶数
- 第一次起跳:
pos
为偶数,跳跃距离为奇数
(1),此次跳跃之后的位置为pos-1
,pos
变为偶数-奇数==奇数
; - 第二次起跳:
pos
为奇数,跳跃距离为偶数
(2),此次跳跃之后的位置为pos-1+2
,pos
变为奇数+偶数==奇数
; - 第三次起跳:
pos
为奇数,跳跃距离为奇数
(3),此次跳跃之后的位置为pos-1+2+3
,pos
变为奇数+奇数==偶数
; - 第四次起跳:
pos
为偶数,跳跃距离为偶数
(4),此次跳跃之后的位置为pos-1+2+3-4
,pos
变为偶数-偶数==奇数
;
此时我们继续往下推的时候,发现是4次跳跃就会抵消一次-(n-2)+(n-1)+n-(n+1)==0
。
那么我们只需要判断n是否可以整除4,如果不能就算出会多出几步,多出的步数就按照我们刚才推出来的规律模拟出来即可。
起跳位置x为奇数
- 第一次起跳:
pos
为奇数,跳跃距离为奇数
(1),此次跳跃之后的位置为pos+1
,pos
变为奇数+奇数==偶数
; - 第二次起跳:
pos
为偶数,跳跃距离为偶数
(2),此次跳跃之后的位置为pos+1-2
,pos
变为偶数-偶数==偶数
; - 第三次起跳:
pos
为偶数,跳跃距离为奇数
(3),此次跳跃之后的位置为pos+1-2-3
,pos
变为偶数-奇数==奇数
; - 第四次起跳:
pos
为奇数,跳跃距离为偶数
(4),此次跳跃之后的位置为pos+1-2-3+4
,pos
变为奇数+偶数==奇数
;
此时我们继续往下推的时候,发现奇数的时候也是4次跳跃就会抵消一次(n-2)-(n-1)-n+(n+1)==0
。
那么我们只需要判断n是否可以整除4,如果不能就算出会多出几步,多出的步数就按照我们刚才推出来的规律模拟出来即可。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=1e5+100;
int a[maxn];
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
ll x,n;
cin>>x>>n;
if(n==0) cout<<x<<endl; //特判掉不会跳跃的时候
else if(x%2==0){
if(n%4==0) cout<<x<<endl;
else if(n%4==1)
cout<<x-n<<endl;
else if(n%4==2)
cout<<x+1<<endl;
else cout<<x+1+n<<endl;
}
else{
if(n%4==0) cout<<x<<endl;
else if(n%4==1)
cout<<x+n<<endl;
else if(n%4==2)
cout<<x-1<<endl;
else cout<<x-1-n<<endl;
}
}
}
C - Minimum Extraction (前缀和+模拟)
比赛链接:https://codeforces.com/contest/1607/problem/C
题目大意
现给出一个长度为 n n n的数组 a a a。
每次我们都会选中数组 a a a中最小的数字 k k k,然后让数组 a a a中其他的数字减去 k k k,再把 k k k从数组中抹除掉,这样数组 a a a就变成了数组 a ′ a' a′, l e n ( a ′ ) = l e n ( a ) − 1 len(a')=len(a)-1 len(a′)=len(a)−1。
请你求出在数组 a a a从长度为 n n n到长度为 1 1 1的过程中, k k k的最大值是多少。
思路
先对数组排序,顺序为由小到大。然后暴力出所有k的值,找最大值。
(当我们删去 m m m个数字之后,剩下的数组中的 k k k值为a[m+1]减去前m个数的和
,但还不至于用前缀和数组去做。)
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
ll a[maxn];
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
ll ans=a[0];
ll maxx=a[0];
for(int i=1;i<n;i++){
a[i]-=ans;
maxx=max(a[i],maxx);
ans+=a[i];
}
cout<<maxx<<endl;
}
}
D - Blue-Red Permutation (思维+贪心)
比赛链接:https://codeforces.com/contest/1607/problem/D
题目大意
现在有一个长度为 n n n的数组 a a a,数组 a a a中每一位数都有一种颜色: r e d red red / b l u e blue blue。
- 红色的数字可以变化为任意一个大于等于本身的数字;
- 蓝色的数字能够变化成任意一个小于等于本身的数字;
问:数组 a a a是否可以变成 1 1 1 ~ n n n的一种排列组合?
思路
假设有 x x x个蓝色数字, n − x n-x n−x个红色数字,我们要把蓝色数字与红色数字的优势全部发挥,所以最优解就是让这 x x x个蓝色数字产生 1 1 1 ~ x x x的数字,让 n − x n-x n−x个红色数字产生 ( x + 1 ) (x+1) (x+1) ~ n n n的数字。
首先给数组排个序。
我们按照颜色
作为第一优先级,蓝色排在前面,红色排在后面;其次是大小
,小的排在前面,大的排在后面。
接下来:
- 如果 a [ i ] a[i] a[i]的颜色是蓝色,但是 a [ i ] < i a[i]<i a[i]<i,此时它无论如何也不能变成 i i i,所以是 N O NO NO;
- 如果 a [ i ] a[i] a[i]的颜色是红色,但是 a [ i ] > i a[i]>i a[i]>i,此时它无论如何也不能变成 i i i,所以也是 N O NO NO;
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
struct node
{
int x;
char c;
}a[maxn];
bool cmp(node z,node k){
if(z.c==k.c)
return z.x<k.x;
else
return z.c<k.c;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n;
string ss;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i].x;
cin>>ss;
for(int i=0;i<n;i++)
a[i].c=ss[i];
sort(a,a+n,cmp);
int flag=1;
for(int i=0;i<n;i++){
if(a[i].c=='R'&&a[i].x>i+1){
flag=0;
break;
}
if(a[i].c=='B'&&a[i].x<i+1){
flag=0;
break;
}
}
if(flag) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
E - Robot on the Board 1(思维)
比赛链接:https://codeforces.com/contest/1607/problem/E
题目大意
现在你的手上有一个机器人,而桌子上是一个大小 n ∗ m n*m n∗m的方格板。
你现在给机器人输入了一串指令,指令中包括:
- U U U:机器人从 ( i , j ) (i,j) (i,j)移动到 ( i − 1 , j ) (i-1,j) (i−1,j);
- D D D:机器人从 ( i , j ) (i,j) (i,j)移动到 ( i + 1 , j ) (i+1,j) (i+1,j);
- L L L:机器人从 ( i , j ) (i,j) (i,j)移动到 ( i , j − 1 ) (i,j-1) (i,j−1);
- R R R:机器人从 ( i , j ) (i,j) (i,j)移动到 ( i , j + 1 ) (i,j+1) (i,j+1);
机器人一旦越过边界就会停止运转。
问:把机器人放在哪个位置开始运作才能使得执行的指令最多?
思路
我们将机器人的移动拆成两个一维的方向来思考。
横向移动
假设机器人当前处于 y = 0 y=0 y=0的位置。
此时我们开始执行整条指令,中间过程中记录一下可以到达的最左位置 m i n y miny miny与最右位置 m a x y maxy maxy。
当 m a x y − m i n y + 1 = = m maxy-miny+1==m maxy−miny+1==m时,说明此时达到了左右移动范围的最大值,那么起点的 y y y值就应该是 1 − m i n y 1-miny 1−miny。
竖向移动
假设机器人当前处于 x = 0 x=0 x=0的位置。
此时我们开始执行整条指令,中间过程中记录一下可以到达的最上方位置 m i n x minx minx与最下方位置 m a x x maxx maxx。
当 m a x x − m i n x + 1 = = n maxx-minx+1==n maxx−minx+1==n时,说明此时达到了上下移动范围的最大值,那么起点的 x x x值就应该是 1 − m i n x 1-minx 1−minx。
灵感来源于电音大佬的讲解:https://www.bilibili.com/video/BV1r34y1o7UC。
AC代码
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2e5+100;
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--){
int n,m;
string ss;
cin>>n>>m;
cin>>ss;
int pos=0;
int minx=0,maxx=0;
int x,y;
for(int i=0;i<ss.size();i++){
if(maxx-minx+1>=m) break;
if(ss[i]=='L') pos--;
if(ss[i]=='R') pos++;
minx=min(minx,pos);
maxx=max(maxx,pos);
}
y=1-minx;
pos=0,maxx=0,minx=0;
for(int i=0;i<ss.size();i++){
if(maxx-minx+1>=n) break;
if(ss[i]=='U') pos--;
if(ss[i]=='D') pos++;
minx=min(minx,pos);
maxx=max(maxx,pos);
}
x=1-minx;
cout<<x<<" "<<y<<endl;
}
}
后话
感谢阅读,希望能对你产生一点用处。
以下台词取自《银魂》第32集:
(求解新八在万事屋中的地位(lll¬ω¬))