B.チェスチーター(ソート+貪欲)Codeforcesグローバルラウンド11

元の質問へのリンク: https //codeforces.com/contest/1427/problem/B

ここに写真の説明を挿入
テストサンプル

入力
8
5 2
WLWLL
6 5
LLLWWL
7 1
LWLWLWL
15 5
WWWLLLWWWLLLWWW
40 7
LLWLWLWWWLWLLWLWWWLWLLWLLWLLLLWLLWWWLWWL
1 0
L
1
L
6 1
WLLWLWの
出力
7
11
6
26
46
0
1
6

注意

最初のテストケースの説明結果を変更する前のスコアは2です。実際、最初のゲームに勝ったので1ポイントを獲得し、3番目のゲームにも勝ったので、さらに1ポイントを獲得しました(2番目のゲームに負けたため2ではありません)。
チートする最適な方法は、2番目と4番目のゲームの結果を変更することです。そうすることで、最初の4つのゲームに勝つことになります(結果の文字列はWWWWLになります)。したがって、新しいスコアは7 = 1 + 2 + 2 + 2です。最初のゲームで1ポイント、2番目、3番目、4番目のゲームで2ポイントです。

2番目のテストケースの説明結果を変更する前のスコアは3です。実際、4番目のゲームに勝ったため、1ポイントを獲得し、5番目のゲームにも勝ったため、さらに2ポイントを獲得しました(前のゲームにも勝ったため)。
チートする最適な方法は、1番目、2番目、3番目、6番目のゲームの結果を変更することです。そうすることで、すべてのゲームに勝つことになります(結果の文字列はWWWWWWになります)。したがって、新しいスコアは11 = 1 + 2 + 2 + 2 + 2 + 2です。最初のゲームで1ポイント、他のすべてのゲームで2ポイントです。

意味:あなたはnnを持っていますn回の連続試合の勝ち負け。現在のスコアリングルールは次のとおりです。ゲームに勝った場合、スコアは1です。連勝に属している場合、スコアは2です。つまり、現在のゲームに勝ち、前のゲームも勝った場合、現在のゲームスコアは2になります。今、あなたはkkを実行することができますK修正操作、修正後に取得できる最大スコアを尋ねます。

問題解決のアイデア:非常に良い質問です。最初に知っておく必要があるのは、スコアをどのように計算するかです。仮定勝ったゲームの数は勝ち勝ちw i n sの場合、前のゲームに勝てなかった勝利の数は、wins _ streaks; wins \ _streaks;です。w i n s _ s t r e a k s ;の場合、スコアの状況は、score = wins ∗ 2 −​​ wins _ streaks score = wins * 2-wins \ _streakss c o r e=w i n s2W I N S _ S T R eはK計算原理はスコアがあると仮定することである2 22μwins_streaks wins \ _streaksW I N S _ S T R eはK sはのスコアである11なので、超過分を差し引きます。これは私たちが何もしなかったスコアです。これで操作を変更できるようになりました。次に、失うものと変更する場所を変更する必要があります。これが解決したい問題です。貪欲の原則によると、我々はできる場合ddは2勝の間のギャップをd(つまり、負けたゲームの数)が勝つため、今回は最も多くのポイントを獲得します。2×d2 \ timesdを取得しただけではないからです2××dのスコアは、右側の連勝に変える必要があります。これはもう1ポイントです。したがって、私たちのタスクはギャップを埋めることと同じです。埋めるギャップがない場合でも、最大で2×k 2 \ timeskを取得できます。2××kのスコア、つまり、ギャップを埋めるたびに、もう1ポイントを追加します。これは、1勝_ストリーク---勝\ _ストリーク-に相当します。w i n s _ s t r e a k s操作。これによると、ギャップの長さを累積して、埋めることができるギャップを埋めるだけです。最終的なスコアの計算式は、引き続き勝ち×2 −勝ち_ストリーク勝ち\回2勝\ _ストリークw i n s××2W I N S _ S T R eはKしたがって、この質問は簡単に解決でき、コードで説明されているいくつかの詳細に注意を払う必要があります。

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