Codeforces Round #605 (Div. 3)
Posted zrcsy
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #605 (Div. 3)相关的知识,希望对你有一定的参考价值。
A. Three Friends
题目大意
给你三个数(a,b,c),每个数可以选择向左,向右或者原地不动,求(min left(left|a-b
ight|+left|a-c
ight|+left|b-c
ight|
ight)的值)
解题思路
- 先按定义求出答案,如果三个数都想等的话,就直接输出0,如果有两个数连续的话就减去(2),否则减去(4)。
依然先按定义求出答案,如果小于4,输出0,否则减去4输出。
AC代码1
#include <bits/stdc++.h>
const int maxn = 1e5+100;
typedef long long ll;
using namespace std;
int q;
ll a[4];
int main()
{
// freopen("data.txt","r",stdin);
cin>>q;
while(q--)
{
for(int i=0;i<3;i++)
{
cin>>a[i];
}
sort(a,a+3);
ll res = a[1]-a[0]+a[2]-a[0]+a[2]-a[1];
if(a[0]==a[1]&&a[1]==a[2]){
}
if(a[0]==a[1]&&a[1]+1==a[2]){
res-=2;
}else if(a[1]==a[2]&&a[0]+1==a[1]){
res-=2;
}else{
res-=4;
}
res = max(1LL*0,res);
cout<<res<<endl;
}
}
AC代码2
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int main()
{
int q;
cin>>q;
while(q--){
int a,b,c;
cin>>a>>b>>c;
int res = abs(a-b)+abs(b-c)+abs(a-c);
res = (res>4)?res-4:0;
cout<<res<<endl;
}
}
B. Snow Walking Robot
题目大意
在一个方格中,从(0,0)点开始出发,每次可以向上,向下,向右,向左前进一个格子,分别用(U,D,R,L)字符表示,给你一个只包含(U,D,R,L)的字符串,删除尽可能少的字符并且重新排序,同时每个点最多经过一次,使得最后回到(0,0)这个点,输出最后的字符串。
解题思路
分别统计(U,D,R,L)的个数,要使得最后回到(0,0)这个点,那么(U)和(D)字符的个数必须一样,(R)和(L)字符的个数必须一样,则取两者的最大值,再分别输出即可,这里要求一个点最多经过一次,只要(U,D,R,L)中任意一个字符的个数为(0),字符的长度最多为(2)。
AC代码
#include <bits/stdc++.h>
const int maxn = 1e5+100;
typedef long long ll;
using namespace std;
int main()
{
// freopen("data.txt","r",stdin);
int q;
cin>>q;
while(q--){
string s;
cin>>s;
int a=0,b=0,c=0,d=0;
for(int i=0;i<s.size();i++){
if(s[i]=='U'){
a++;
}else if(s[i]=='D'){
b++;
}else if(s[i]=='R'){
c++;
}else{
d++;
}
}
int res = min(a,b);
int res2 = min(c,d);
if(res==0||res2==0){
res2=min(res2,1);
res = min(res,1);
}
cout<<(res+res2)*2<<endl;
for(int i=0;i<res;i++){
cout<<'U';
}
for(int i=0;i<res2;i++){
cout<<'R';
}
for(int i=0;i<res;i++){
cout<<'D';
}
for(int i=0;i<res2;i++){
cout<<'L';
}
cout<<endl;
}
}
C. Yet Another Broken Keyboard
题目大意
给你一个字符串(s),同时给你(k)个字符的字符数组(t),求(s)中只包含(t)中字符的字串个数。
解题思路
首先先遍历字符数组(t),用另外一个数组(str)标记每个字符是否可用,遍历整个字符串,求出每个符合要求的最长字串长度(len),然后答案加上(frac{n imesleft(n+1 ight)}{2})即可。
AC代码
#include <bits/stdc++.h>
const int maxn = 1e5+100;
typedef long long ll;
using namespace std;
bool str[200];
int main()
{
// freopen("data.txt","r",stdin);
for(int i=0;i<200;i++){
str[i]=true;
}
int n,k;
cin>>n>>k;
string s;
cin>>s;
getchar();
for(int i=0;i<k;i++){
char c;
cin>>c;
str[c-'0']=false;
}
ll res=0;
int cnt=0;
for(int i=0;i<s.size();i++){
if(str[s[i]-'0']==false){
cnt++;
}else{
res+=1LL*cnt*(1LL*cnt+1)/2;
cnt=0;
}
}
res+=1LL*cnt*(1LL*cnt+1)/2;
cout<<res<<endl;
}
D. Remove One Element
题目大意
给你一个包含(n)个数字的数组(a),可以删除数组(a)中最多一个数组,求最长严格递增子数组的长度。
解题思路
这道题是个典型的动态规划的题目。
数组dp[i]表示以(a_i)为起点的最长子数组长度,转移方程为:
[dp[i]=egin{cases}
1 & i=n 1 & a[i]geq a[i+1] dp[i+1]+1 & a[i]<a[i+1] end{cases}
]
数组dp2[i]表示以(a_i)为终点的最长子数组长度,转移方程为:
[dp2[i]=egin{cases}
1 & i=1 1 & a[i-1]geq a[i] dp[i-1]+1 & a[i-1]<a[i] end{cases}
]
遍历整个数组(a),如果(a_{i+1}> a_{i-1}),那么结果为(max(result,dp2[i+1]+dp[i-1]))
AC代码
#include <bits/stdc++.h>
const int maxn = 2e5+100;
typedef long long ll;
using namespace std;
int number[maxn];
ll dp[maxn];
ll dp2[maxn];
int main()
{
// freopen("data.txt","r",stdin);
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>number[i];
}
dp[n]=1;
ll res=1;
for(int i=n-1;i>=1;i--){
if(number[i]<number[i+1]){
dp[i] = dp[i+1]+1;
res = max(res,dp[i]);
}else{
dp[i]=1;
}
}
dp2[0]=0;
for(int i=1;i<=n;i++){
if(number[i]>number[i-1]){
dp2[i] = dp2[i-1]+1;
}else{
dp2[i]=1;
}
}
for(int i=1;i<=n;i++){
if(i+1<=n&&number[i+1]>number[i-1]){
res=max(res,dp[i+1]+dp2[i-1]);
}
}
cout<<res<<endl;
}
E. Nearest Opposite Parity
题目大意
给你一个由(n)个整数组成的数组。 一键移动,您可以从位置(i)跳到位置(i-a_i)(如果(1leq (i-a_i)))或跳到位置(i+a_i)(如果(i+a_i leq n))。
对于从(1)到(n)的每个位置(i),您想知道到达任何位置(j)所需的最小移动次数,以使(a_j)与(a_i)具有相反的奇偶性(即,如果(a_i)为奇数,则(a_j)必须为偶数,反之亦然)。
解题思路
- 思路一:反向建立图,对于偶数的情况,偶数(a_i)到奇数(a_j)的最小移动次数反向建图之后就是所有奇数(a_j)到(a_i)的最短路径的长度即位答案,但偶数有那么多个,每个偶数都去计算所有奇数到它的最短路径,时间复杂度太高,这个时候就可以使用超级源点,设一个点到所有奇数的距离为(0),跑一个最短路径出来,所有偶数的答案都出来了。对于奇数的情况也是一样的。即找到两个超级源点跑两次最短路径。
思路二:同样是反向建图,但可以不用最短路径,在建图的过程中找到跳转一次就可以到达的点放入队列中,然后BFS搜索即可。这样的代码量可以减少很多。
AC代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f3f3f3f
const int maxn=2e5+10;
typedef long long ll;
using namespace std;
typedef pair<long long,int> P;
struct edge
{
int to,cost;
};
vector<edge>G[maxn];
int number[maxn];
ll d[maxn];
int n;
ll res[maxn];
void dijks(int s)
{
priority_queue<P,vector<P>,greater<P> >pq;
fill(d,d+n+1,INF);
d[s]=0;
pq.push(P(0,s));
while(!pq.empty())
{
P p=pq.top();
pq.pop();
int v=p.second;
if(d[v]<p.first)
continue;
else
{
for(int i=0;i<G[v].size();i++)
{
if(d[G[v][i].to]>d[v]+G[v][i].cost)
{
d[G[v][i].to]=d[v]+G[v][i].cost;
pq.push(P(d[G[v][i].to],G[v][i].to));
}
}
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++){
cin>>number[i];
}
for(int i=1;i<=n;i++){
if(number[i]+i<=n){
edge e = {i,1};
G[number[i]+i].push_back(e);
}
if(i-number[i]>=1){
edge e = {i,1};
G[i-number[i]].push_back(e);
}
}
for(int i=1;i<=n;i++){
if(number[i]%2==1){
edge e = {i,0};
G[0].push_back(e);
}
}
dijks(0);
for(int i=1;i<=n;i++){
if(number[i]%2==0){
res[i] = d[i];
}
}
G[0].clear();
for(int i=1;i<=n;i++){
if(number[i]%2==0){
edge e = {i,0};
G[0].push_back(e);
}
}
dijks(0);
for(int i=1;i<=n;i++){
if(number[i]%2==1){
res[i] = d[i];
}
}
for(int i=1;i<=n;i++){
if(res[i]>=INF){
cout<<"-1"<<" ";
}else{
cout<<res[i]<<" ";
}
}
cout<<endl;
}
F. Two Bracket Sequences
题目大意
给你两个括号字符串(s,t),找到一个最短合法字符串满足其子序列包括字符串(s,t)。
解题思路
这道题也是一道动态规划的题,不过这道题是三维的动态规划。(dp[i][j][k])表示(s)串匹配到(i),(t)串匹配到(j)的时候有(k)个(()没有匹配的最小长度。转移方程不是很好写,具体看代码。因为要求子序列包含(s),(t)并且最后的字符串尽可能的短,那么就应该用字符串(s),(t)尽可能的构造合法的括号
AC代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
const int maxn = 2e2+40;
typedef long long ll;
using namespace std;
int n,m;
string s,t;
bool res[maxn][maxn][2*maxn];
int dp[maxn][maxn][2*maxn];
int dfs(int i,int j,int cnt){
if(i==n&&j==m)
return cnt;
if(cnt>n+m){
return 1e9;
}
if(~dp[i][j][cnt]){
return dp[i][j][cnt];
}
int op1 = 1 + dfs(i+(i<n && s[i]=='('),j + (j<m && t[j]=='(') ,cnt+1),op2 = 1e9;;
if(cnt){
op2 = 1 + dfs(i+(i<n && s[i]==')'),j + (j<m && t[j]==')') ,cnt-1);
}
res[i][j][cnt]=op1<op2;
return dp[i][j][cnt]=min(op1,op2);
}
int main()
{
ios::sync_with_stdio(false);
memset(dp,-1,sizeof(dp));
cin>>s>>t;
n = s.size();
m = t.size();
dfs(0,0,0);
int i=0,j=0,cnt=0;
while(i<s.size()||j<t.size()){
if(res[i][j][cnt]){
i+=(i<n && s[i]=='(');
j+=(j<m && t[j]=='(');
cnt++;
cout<<"(";
}else{
i+=(i<n && s[i]==')');
j+=(j<m && t[j]==')');
cnt--;
cout<<")";
}
}
while(cnt--){
cout<<")";
}
cout<<endl;
}
总结
终于有一次能把(CodeForces)上的题完整的补完一次了。(A)题真的傻了,那么简单的,当时居然卡了好一会儿。(B),(C,D)题比较简单,只是(D)有个小细节没有处理好,(wa)了两次。(E),(F)是赛后交流之后补的。终于涨分了,呜呜呜
以上是关于Codeforces Round #605 (Div. 3)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #605 (Div. 3) ABCDE 题解
Codeforces Round #605(Div3)A~E
Codeforces Round #605 (Div. 3) E. Nearest Opposite Parity
Codeforces Round #605 (Div. 3) E - Nearest Opposite Parity
Codeforces Round #605 (Div. 3) F. Two Bracket Sequences 三维dp
Codeforces Round #605 (Div. 3) E - Nearest Opposite Parity (超级源点)