Official

C - T-shirts Editorial by mechanicalpenciI


まず、予定のない日が入るたびに全てのTシャツを洗濯でき、着用できるTシャツの枚数がリセットされることから、\(N\) 日間の予定のうち 0 で区切られている部分についてはそれぞれ独立に考えることができます。 また、問題文の条件より、追加で \(a\) 枚ロゴ入りの T シャツを購入すれば条件をみたすように着用できるとき、\(a\) 枚以上であれば何枚購入しても条件をみたすように着用できます。
よって、\(S\) の中に 0\(c_0\) 個含まれており、具体的には \(d_1,d_2,\ldots, d_{c_0}\) 文字目が 0 であった時、 \(1\) 日目から \((d_1-1)\) 日目まで、 \((d_1+1)\) 日目から \((d_2-1)\) 日目まで、 \(\ldots\)\((d_{c_0-1}+1)\) 日目から \((d_{c_0}-1)\) 日目まで、 \((d_{c_0}+1)\) 日目から \(N\) 日目まで のぞれぞれの予定において、その予定に対する条件をみたすように T シャツを着用するために購入する必要のあるロゴ入りの T シャツの最低枚数が求まれば、求めるべき答えはそれらのうちの最大値として求めることができます。


次に、12 のみからなる長さ \(k\) の文字列 \(T\) に対応する予定について条件をみたすように T シャツを着用するために最低何枚の T シャツを購入する必要があるかについて考えます。
\(T\) の中に 1\((k-x)\) 個、 2\(x\) 個含まれているとき、少なくとも次の \(2\) つの条件がみたされる必要があります。

  • ロゴ入りのT シャツを \(x\) 枚以上所持している。
  • 無地の T シャツとロゴ入りのT シャツをあわせて \(k\) 枚以上所持している。

これは、それぞれ、競技プログラミングのイベントがある日にはロゴ入りの T シャツを着用する必要があること、食事またはイベントがある日にはいずれかの T シャツを \(1\) 枚着用しなければならないことから明らかです。

逆にこれが満たされるとき、すなわち高橋君が \(y=\max(x,k-M)\) 枚以上ロゴ入り T シャツを購入していたとき、高橋君は次のようにして条件を満たすように T シャツを着用することができます。

  • 食事の予定がある時、洗濯済みの無地の T シャツが残っているならばそのうちの \(1\) 枚を、そうでないならばロゴ入りの T シャツを着用する。
  • 競技プログラミングのイベントがあるとき、ロゴ入りの T シャツを着用する。
証明 高橋君が $y=\max(x,k-M)$ 枚以上ロゴ入り T シャツを購入し、上記のように服を着用したとき、$t$ $(1\leq t\leq k)$ 日目に着用できる Tシャツが存在しなかったとします。両方の T シャツがあわせて $k$ 枚以上あることから、(無地とロゴ入りあわせて)少なくとも $1$ 枚の T シャツは洗濯済みの状態で存在しています。よって、あり得るならば競技プログラミングのイベントがある日に無地の T シャツのみ着用可能であるような状況となります。しかし、このとき(上で述べたシャツの選び方から) $t-1$ 日目までの食事の予定でロゴ入りの T シャツを着用していることはないため、$t$ 日目までに競プロのイベントが $y+1$ 回以上行われたことになります。しかし、$k$ 日間の間に競技プログラミングのイベントは高々 $x(\leq y)$回しか行われないためこれはあり得ません。よって$k$ 日間の間に着用できる Tシャツが存在しなることはなく、高橋君は $k$ 日間条件を満たすように T シャツを着用することができます。


これらの事から、\((k-x)\) 個の 1 と、\(x\) 個の 2 からなるような \(T\) に対応する\(k\) 日間の予定について、条件をみたすように T シャツを着用するために購入する必要のある最小枚数は \(\max(x,k-M)\) 枚であることが分かります。

あとは、0 で区切られた各文字列についてこの値を求め、さらにその中の最大値を求めれば良いです。

これを求めるには例えば、12 の登場回数を数えながら \(S\) を左から見ていき、0 または文字列の終端が来るたびに \(y=\max(x,k-M)\) を求めカウントをリセットすれば良いです。 このとき、\(S\) の各文字を \(2\) 回以上参照する必要はなく、計算量は \(O(N)\) となるため、十分高速です。
よって、この問題を解くことができました。
なお、\(S\) の末尾に 0 を付け加えることで文末と 0 が来た時の処理を統一して行うことができます。

c++ による実装例:

#include <bits/stdc++.h>
using namespace std;

int main(void){
	int n,m;
	int ans=0;
	int x=0,y=0;
	string s;

	cin>>n>>m;
	cin>>s;
	s+="0";

	for(int i=0;i<=n;i++){
		if(s[i]=='0'){
			ans=max(ans,max(x+y-m,y));
			x=0,y=0;
		}
		if(s[i]=='1')x++;
		if(s[i]=='2')y++;
	}
	
	cout<<ans<<endl;
	return 0;
}

posted:
last update: