Codeforces Round #605 (Div. 3)
地址:http://codeforces.com/contest/1272
A. Three Friends
仔细读题能够发现|a-b| + |a-c| + |b-c| = |R-L|*2 (其中L = min{a, b, c}, R = max{a, b, c})
那么本题的移动条件就只考虑两个端点L, R即可,答案即为 |(L+1)-(R-1)| 即L向右移动1,R向左移动1,在此之前判断一下原L,R之间的距离是否<=2,<=2输出0
#include <bits/stdc++.h>
using namespace std;
int q, a[3];
int main(){
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> q;
while( q-- ){
for( int i=0; i<3; i++ ) cin >> a[i];
sort(a, a+3);
if( a[2]-a[0]<=2 ) cout << "0" << endl;
else cout << (a[2]-a[0]-2)*2 << endl;
}
return 0;
}
B.Snow Walking Robot
这题比赛时没做出来??理解题意出了锅。
思路:如果能够回到(0, 0)需满足数量U=D且R=L,只需要上下方向选min(U, D),左右方向选min(L, R)。
如果U=0或D=0那么就要删除所有的另外一个方向,且将左右方向置为1(min(L, R)>0),对于R和L也一样要满足该条件,上下方向置为1(min(U, D)>0)
然后最后组合的时候只需要让路径构成一个环即可,这个组合可以任意组合,做题的时候卡在这了。。。
#include <bits/stdc++.h> using namespace std; int q, cl, cr, cu, cd; string s; int main(){ // freopen("in.txt", "r", stdin); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> q; while( q-- ){ cin >> s; cl = cr = cu = cd = 0; for( char i:s ){ cl += i=='L'; cr += i=='R'; cu += i=='U'; cd += i=='D'; } cu = min(cu, cd); cl = min(cl, cr); if( cu==0 || cl==0 ){ cl = min(1, cl); cu = min(1, cu); } string ans; for( int i=0; i<cl; i++ ) ans += 'R'; for( int i=0; i<cu; i++ ) ans += 'U'; for( int i=0; i<cl; i++ ) ans += 'L'; for( int i=0; i<cu; i++ ) ans += 'D'; cout << ans.size() << endl << ans << endl; } return 0; }
C.Yet Another Broken Keyboard
给k个字母问这k的字母能构成字符串s中多少个子串。
set存一下这k个字母,对s中每一段连续的可以在set中查找到的分别进行统计汇总即可,每一段长度len_i对答案的贡献为(len_i)*(len_i+1)/2.
#include <bits/stdc++.h> using namespace std; typedef long long ll; int n, k; string s; set<char> a; ll ans, tmp; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> k >> s; for( int i=0; i<k; i++ ){ char ch; cin >> ch; a.insert(ch); } int len = s.size(); for( int i=0; i<len; i++ ){ if( a.find(s[i])!=a.end() ) tmp ++; else{ ans += tmp*(tmp+1)/2; tmp = 0; } } if(tmp) ans += tmp*(tmp+1)/2; cout << ans << endl; return 0; }
D. Remove One Element
三遍预处理 + 一遍原序列
第一遍预处理处理出来一个数不删的最大长度。
第二遍预处理从i from 1~n记录l[i]从左到右递增的最长连续序列长度。
第三遍预处理从i from n~1记录r[i]从右到左递减的最长连续序列长度。
最后跑原序列i from 1~n判断删除i之后的结果能否更新第一遍记录的答案
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; int a[maxn], n, l[maxn], r[maxn], ans; int main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for( int i=0; i<n; i++ ) cin >> a[i]; int tmp = 1; for( int i=1; i<n; i++ ){ if( a[i]>a[i-1] ) tmp++; else tmp = 1; ans = max(ans, tmp); } l[0] = 1; for( int i=1; i<n; i++ ){ if( a[i]>a[i-1] ) l[i] = l[i-1]+1; else l[i] = 1; } r[n-1] = 1; for( int i=n-2; ~i; i-- ){ if( a[i]<a[i+1] ) r[i] = r[i+1]+1; else r[i] = 1; } for( int i=1; i<n-1; i++ ) if( a[i-1]<a[i+1] ) ans = max(ans, l[i-1]+r[i+1]); cout << ans << endl; return 0; }
E.Nearest Opposite Parity
比赛时dfs写MLE,时间不够放弃。
预处理 + bfs通过,使用bfs理由->最短路
预处理出来答案为1的点,然后放进队列,同时将所有点i from 1~n可以跳到的位置i-a[i]和i+a[i]连边然后bfs
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 5; const int inf = 0x3f3f3f3f; int n, a[maxn], ans[maxn]; vector<int> p[maxn]; int main(){ memset( ans, -1, sizeof(ans) ); scanf("%d", &n); for( int i=0; i<n; i++ ) scanf("%d", &a[i]); queue<int> q; for( int i=0; i<n; i++ ){ if( i-a[i]>=0 ){ p[i-a[i]].push_back(i); if( a[i-a[i]]%2 != a[i]%2 ) ans[i] = 1; } if( i+a[i]<n ){ p[i+a[i]].push_back(i); if( a[i+a[i]]%2 != a[i]%2 ) ans[i] = 1; } if( ans[i]==1 ) q.push(i); } while( q.size() ){ int x = q.front(); q.pop(); for( auto i:p[x] ){ if( ans[i]==-1 && a[i]%2==a[x]%2 ){ ans[i] = ans[x]+1; q.push(i); } } } for( int i=0; i<n; i++ ){ printf("%d", ans[i]); if( i==n-1 ) puts(""); else putchar(' '); } return 0; }