B. Chess Cheater(排序+贪心)Codeforces Global Round 11

原题链接: https://codeforces.com/contest/1427/problem/B

在这里插入图片描述
测试样例

input
8
5 2
WLWLL
6 5
LLLWWL
7 1
LWLWLWL
15 5
WWWLLLWWWLLLWWW
40 7
LLWLWLWWWLWLLWLWWWLWLLWLLWLLLLWLLWWWLWWL
1 0
L
1 1
L
6 1
WLLWLW
output
7
11
6
26
46
0
1
6

Note

Explanation of the first testcase. Before changing any outcome, the score is 2. Indeed, you won the first game, so you got 1 point, and you won also the third, so you got another 1 point (and not 2 because you lost the second game).
An optimal way to cheat is to change the outcomes of the second and fourth game. Doing so, you end up winning the first four games (the string of the outcomes becomes WWWWL). Hence, the new score is 7=1+2+2+2: 1 point for the first game and 2 points for the second, third and fourth game.

Explanation of the second testcase. Before changing any outcome, the score is 3. Indeed, you won the fourth game, so you got 1 point, and you won also the fifth game, so you got 2 more points (since you won also the previous game).
An optimal way to cheat is to change the outcomes of the first, second, third and sixth game. Doing so, you end up winning all games (the string of the outcomes becomes WWWWWW). Hence, the new score is 11=1+2+2+2+2+2: 1 point for the first game and 2 points for all the other games.

题意: 你有 n n n次依次进行比赛的胜败情况。现得分规则如下:如果你赢了一场比赛,那么得分为1,如果你是属于连胜,那么得分为2。也就是说,如果你当前比赛赢了,且上一场比赛也赢了,那么当前比赛得分为2。现在你可以进行 k k k次修改操作,问经过修改后所能得到的最大分数。

解题思路: 一道非常好的问题。我们首先要知道的一点就是我们怎么计算分数?假设赢的场数为 w i n s wins wins,赢得场数的上一把没有赢的个数为 w i n s _ s t r e a k s ; wins\_streaks; wins_streaks;,那么得分情况就是 s c o r e = w i n s ∗ 2 − w i n s _ s t r e a k s score=wins*2-wins\_streaks score=wins2wins_streaks 计算原理即是假设得分都是 2 2 2,而 w i n s _ s t r e a k s wins\_streaks wins_streaks这种是得分为 1 1 1的,故减去多余的。这就是我们没有进行任何操作的得分。现在你可以进行操作修改,那么我们肯定是将输的变赢的,将哪里的改变,这是我们要解决的问题。根据贪心原则,如果我们能将两场赢的之间的间隙 d d d(即输的场数)都变为赢的,那么这个时候我们得到的分是最多的。 因为我们不仅获得了 2 × d 2\times d 2×d的分数,还是得右边一场变为连胜,也多了一分。所以我们的任务就相当于是用在补间隙了,之后如果没有间隙可以补了,那么我们最多也还是可以获得 2 × k 2\times k 2×k的分数,也就是说,我们每补一个间隙,就多一分,也就相当于进行了一次 w i n s _ s t r e a k s − − wins\_streaks-- wins_streaks操作。那么根据这个我们只需要累计间隙的长度,再将我们能补的间隙补完即可。最后得分的计算公式还是 w i n s × 2 − w i n s _ s t r e a k s wins\times 2-wins\_streaks wins×2wins_streaks。故此题易解,要注意一些细节,已在代码中说明。

AC代码

/*
*邮箱:[email protected]
*blog:https://me.csdn.net/hzf0701
*注:文章若有任何问题请私信我或评论区留言,谢谢支持。
*
*/
#include<bits/stdc++.h>	//POJ不支持

#define rep(i,a,n) for (int i=a;i<=n;i++)//i为循环变量,a为初始值,n为界限值,递增
#define per(i,a,n) for (int i=a;i>=n;i--)//i为循环变量, a为初始值,n为界限值,递减。
#define pb push_back
#define IOS ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define fi first
#define se second
#define mp make_pair

using namespace std;

const int inf = 0x3f3f3f3f;//无穷大
const int maxn = 1e5;//最大值。
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll>  pll;
typedef pair<int, int> pii;
//*******************************分割线,以上为自定义代码模板***************************************//

int t,n,k;
string s;
int main(){
    
    
	//freopen("in.txt", "r", stdin);//提交的时候要注释掉
	IOS;
	while(cin>>t){
    
    
		while(t--){
    
    
			cin>>n>>k;
			cin>>s;
			int wins=0,losses=0,wins_streaks=0;
			vector<int> losing_streaks;//这个用于统计间隙。
			rep(i,0,n-1){
    
    
				if(s[i]=='W'){
    
    
					if(i==0||s[i-1]=='L'){
    
    
						//说明是一个赢单数。
						wins_streaks++;
					}
					wins++;//统计原本赢得场数。
				}
				else{
    
    
					losses++;//统计原本数的场数。
					if(i==0||s[i-1]=='W'){
    
        
						//说明一个新的输的间隙开始了。
						losing_streaks.push_back(0);
					}
					losing_streaks.back()++;//尾部输的间隙+1,。
				}
			}
			//知道了这样的操作,接下来进行特判。
			if(k>=losses){
    
    
				//说明我们可以直接补完所有输的场数。
				cout<<2*n-1<<endl;
				continue;
			}
			if(wins==0){
    
    
				//说明我们没有一场赢,那么我们补的话一定是补连续的。
				if(k==0){
    
    
					cout<<0<<endl;
				}
				else{
    
    
					cout<<2*k-1<<endl;
				}
				continue;
			}
			//我们知道我们统计的第一个间隙和最后一个间隙可能没有被w包围。
			if(s[0]=='L'){
    
    
				losing_streaks[0]=inf;
			}
			if(s[n-1]=='L'){
    
    
				losing_streaks.back()=inf;
			}
			sort(losing_streaks.begin(),losing_streaks.end());
			int len=losing_streaks.size();
			wins+=k;
			rep(i,0,len-1){
    
    
				if(losing_streaks[i]>k){
    
    
					break;
				}
				else{
    
    
					wins_streaks--;
					k-=losing_streaks[i];
				}
			}
			cout<<2*wins-wins_streaks<<endl;
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/hzf0701/article/details/109007454
今日推荐