codeforce Round #605(Div.3)
A. Three Friends
题目意思:有三个好朋友a,b,c。他们在一个坐标轴上,他们的位置分别是xa 和xb ,xc,他们三个人都可以往前或者往后走一步,只能走一步。问你他们走了(也可能不走)之后的abs(xa - xb) + abs(xb - xc) + abs(xc - xa )的最小值是多少?
题目分析:我们可以假定朋友a的坐标最小,朋友b比朋友a更大,但是又比朋友c更小,所以朋友c的位置坐标最大。所以我们可以知道,上面那个式子就是两倍的(最大坐标-最小的坐标),所以我们使得它们的距离最小就可以了。所以怎么使得它们的距离最小呢,那肯定是朋友a向朋友c走一步,朋友c向朋友a走一步,这样就会使得距离最小,真的吗??不不不,肯定不是,如果三个朋友都在相同的位置,a走一步,c走一步,那距离不久变大了,所以我们就可以是ans的初值为0;然后将最大的距离减去最小的距离的值 - 2,得到minn,然后去max(minn,ans),如果minn是负数,那就说明它们肯定可以走到一块,所以距离就是0,如果是正数,那就很遗憾了,它们走不到一块,所以就取那个最小值就可以了。
下面看代码:$i + a_i \le n $
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 5 using namespace std; 6 int num[5]; 7 8 int main() 9 { 10 int t; 11 scanf("%d",&t); 12 while(t--) 13 { 14 for(int i = 1; i <= 3; i++) 15 scanf("%d",&num[i]); 16 sort(num+1,num+4); 17 int ans = 0; 18 ans = max(0,num[3] - num[1] - 2); 19 printf("%d\n",2*ans); 20 } 21 return 0; 22 }
B. Snow Walking Robot
题目链接:http://codeforces.com/contest/1272/problem/B
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 6 using namespace std; 7 const int ma = 1e5 + 10; 8 char s[ma]; 9 int n,q,num[10]; 10 int main() 11 { 12 scanf("%d",&q); 13 int ans,len; 14 int minn1,minn2; 15 while(q--) 16 { 17 scanf(" %s",&s); 18 len = strlen(s); 19 for(int i = 0; i < 4; i++) 20 num[i] = 0; 21 for(int i = 0; i < len; i++) 22 { 23 if(s[i] == 'L') 24 num[0]++; 25 else if(s[i] == 'R') 26 num[1]++; 27 else if(s[i] == 'U') 28 num[2]++; 29 else if(s[i] == 'D') 30 num[3]++; 31 } 32 minn1 = min(num[0],num[1]); 33 minn2 = min(num[2],num[3]); 34 if(!minn1 && !minn2) 35 printf("0\n\n"); 36 else 37 { 38 if(!minn1) 39 minn2 = 1; 40 if(!minn2) 41 minn1 = 1; 42 printf("%d\n",2*minn1 + 2*minn2); 43 for(int i = 1; i <= minn1; i++) 44 printf("%c",'L'); 45 for(int i = 1; i <= minn2; i++) 46 printf("%c",'U'); 47 for(int i = 1; i <= minn1 - 1; i++) 48 printf("%c",'R'); 49 for(int i = 1; i <= minn2 - 1; i++) 50 printf("%c",'D'); 51 if(minn1) 52 printf("%c",'R'); 53 if(minn2) 54 printf("%c",'D'); 55 printf("\n"); 56 } 57 } 58 return 0; 59 }
我觉得英语不好的人打cf的比赛很吃亏,题目都看不懂怎么写,要哭了······
这里要注意这句话:visits no cell other than (0,0) two or more times and ends the path in the cell (0,0).它的意思就是除了(0,0)坐标以外只能visit一次。题目字符串合法的标准是,以坐标(0,0)开始,并且以坐标(0,0)结束,在行走的过程中每个坐标只能走一次,问你将不合法的字符串改为合法的字符串所需要的最小值是多少?,当然也有可能无论怎么改都不合法的,那就输出0;
题目分析:我们来分情况讨论一下,第一种是只有一个方向的,那肯定不合法的,怎么走也走不回原点:
第二种:有两个方向。这里又可以分类,一是正反方向,比如左右方向,如果是这样的话,那只能是左右(上下)各走一步;二是竖直方向,比如左上,那肯定也是不合法的。
第三种:有三个方向,那肯定也不能回到原点。
第四种:就是有四个方向。因为要回到原点,所以说往左走了多少步,就要往右走多少步,所以要取一个正反的最小值,l = min(num_l,num_r),h = min(num_u,num_d),这样数量上就满足了,然后我们要满足那两个要求了,那我们肯定不能往左走了,然后就往右边走,所以我们可以L,U,R,D这样样,走一个矩形,这样一下子就解决了两个要求。
代码在上面。
C. Yet Another Broken Keyboard
题目链接:http://codeforces.com/contest/1272/problem/C
c题算是给出了公式,但是要对题意加以理解(我感觉我没理解),根据我所理解的就是还可以用的字母连续的用题目所给的公式n*(n+1)/2,计算字母的个数然后带入公式,将其加起来就可以。这让我明白看不懂的题目猜一下题目意思也行。
看代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <set> 5 6 using namespace std; 7 typedef long long ll; 8 const int ma = 2e5 + 100; 9 char c[ma]; 10 int s[30]; 11 int n,k; 12 ll ans; 13 14 int main() 15 { 16 scanf("%d%d",&n,&k); 17 scanf(" %s",c); 18 getchar(); 19 char ss; 20 for(int i = 1; i <= k; i++) 21 { 22 scanf("%c",&ss); 23 getchar(); 24 s[ss-'a'] = 1; 25 } 26 ll a; 27 ans = 0; 28 a = 0; 29 for(int i = 0; i < n; i++) 30 { 31 if(s[c[i] - 'a']) 32 { 33 a++; 34 if(i == n-1) 35 ans += (a+1)*a/2; 36 } 37 else 38 ans += (a+1)*a/2,a = 0; 39 } 40 printf("%lld",ans); 41 return 0; 42 }
D. Remove One Element
这是最有意思的一道题了,dp题,因为本人不太会dp思想,所以我是左思右想还是不会写,然后就看了一下题解,发现题解讲的简单,实现的也简单,我太菜了,要好好学习dp,多写几道题。
根据题目意思题解是这样定义状态的 Li代表着以位置i开始的最大长度,Ri代表着以i开始的最大增加长度。那怎么实现呢,怎么实现呢。首先这两个数组肯定都有初始值,并且都是1,代表着它们本身,L数组所求的以位置i开始的最大长度所以L要从数组的右边开始,如果num[i] < num[i+1],那么就代表着可以延续下去,所以L[i] = L[i+1] + 1,如果不满足就不延续,遍历一遍数组就可以得到了;那么同样的也可以这样求R数组,但是它要从第二个数开始。然后我们就可以得到这两个数组了,因为题目讲可以将一个数字忽略,所以以i结束的最大长度加上i+2开始的最大长度,历经一边去最大值,如果这样交,你会发现还是过不了,太难过了,怎么老是过不了····,因为少了一种情况就是,数组本身就是递增数组。
下面是代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 5 using namespace std; 6 const int ma = 2e5 + 10; 7 int n,l_len[ma],r_len[ma],num[ma]; 8 9 int main() 10 { 11 scanf("%d",&n); 12 for(int i = 1;i <= n;i++) 13 scanf("%d",&num[i]); 14 for(int i = 1;i <= n;i++) 15 l_len[i] = r_len[i] = 1; 16 int ans = 1; 17 for(int i = n-1;i >= 1;i--) 18 { 19 if(num[i] < num[i+1]) 20 l_len[i] = l_len[i+1] + 1; 21 ans = max(ans,l_len[i]); 22 } 23 for(int i = 2;i <= n;i++) 24 { 25 if(num[i-1] < num[i]) 26 r_len[i] = r_len[i-1] + 1; 27 ans = max(ans,r_len[i]); 28 } 29 for(int i = 1;i < n;i++) 30 { 31 if(num[i] < num[i+2]) 32 ans = max(ans,r_len[i] + l_len[i+2]); 33 } 34 printf("%d",ans); 35 return 0; 36 }
E. Nearest Opposite Parity
题目意思: 这题的题目意思比较简单,主要是给你一组数组,每个数字可以往两个方向走,就如下标 i ,如果 i + num[i] <= n 的话,那么就可以判断 num[i+num[i]] 的奇偶性是不是一样的,如果是的话话,就可以终止了,但是我们需要求每个数找到不同奇偶性的最小数就可以了。
题目分析: 这题分析下去就是一个道搜索题,当你在数字 num[i] 时,你可以往两个方向走,如果可以走的话,一是往 i + num[i] 的方向走,二是往 i - num[i] 的方向走,因为要往两个方向走,并且要找最优解,防止超时,所以选bfs来进行搜索是比较好的。我一开始按照正常的思路,模拟题目所讲的进行搜索,循环遍历数组,每个数再搜索,但很遗憾超时了,虽然我也觉得会超时。后来问了一个大佬,在经过几分钟的讲解之后,我终于知道怎么做了。这里可以反向建边,我们假设每个数字走 i + num[i] 和 i - num[i],如果可以走的话,并且所走的那个数字与num[i] 的奇偶性不一样才有效,将可以立马找到的点作为起点,就是将下标放进队列里。这里我们用vector存边,也就是说 v[i] 里面存的是下标 i 可以到的边,因为这里建立的是反向边,所以就是所有 v[i] 里面的数可以到达 i。解决了这些问题,我们就可以来看一下怎么搜索了。
这上面的分析中,我们可以知道队列里面已经放进去了路径为 1的下标,这也意味着说,剩下的下标肯定是路径超过了 1,所以我们可以从队列中的起点出发,向外面延伸,就比如下标1属于起点,那么如果在v[1]中有数字的话,比如有下标5,也就是说下标 5 可以到达下标 1,如果ans[5] == -1( ans数组是存储答案的数组,并且赋初值为-1),那就说明 num[5] 与 num[1] 的奇偶性肯定是一样的,因为如果不是相同的话,那他们之间的路径肯定是1了,但是这与 ans[5] = -1 相矛盾,所以奇偶性相同,又因为下标1可以一步找到奇偶性不一样的数字,所以ans[5] = ans[1] + 1了,所以相类似的了。
所以这样就保证了奇偶性。
下面看代码:
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <vector> 5 #include <queue> 6 7 using namespace std; 8 const int ma = 2e5 + 10; 9 int n,num[ma],dep[ma]; 10 vector<int> v[ma]; 11 queue<int> q; 12 13 void bfs() 14 { 15 int a; 16 while(!q.empty()) 17 { 18 a = q.front(),q.pop(); 19 for(int i = 0;i < v[a].size();i++) 20 if(dep[v[a][i]] == -1) 21 dep[v[a][i]] = dep[a] + 1,q.push(v[a][i]); 22 } 23 } 24 int main() 25 { 26 scanf("%d",&n); 27 for(int i = 1;i <= n;i++) 28 scanf("%d",&num[i]); 29 int next1,next2; 30 for(int i = 1;i <= n;i++) 31 { 32 next1 = next2 = 0; 33 dep[i] = -1; 34 if(i + num[i] <= n) 35 next1 = i + num[i]; 36 if(i - num[i] >= 0) 37 next2 = i - num[i]; 38 if(next1) 39 v[next1].push_back(i); 40 if(next2) 41 v[next2].push_back(i); 42 if((next1 && num[i]%2 != num[next1]%2) || (next2 && num[i]%2 != num[next2]%2)) 43 dep[i] = 1,q.push(i); 44 } 45 bfs(); 46 for(int i = 1;i <= n;i++) 47 printf("%d ",dep[i]); 48 return 0; 49 }