結果

問題 No.2454 Former < Latter
ユーザー planesplanes
提出日時 2023-09-01 22:23:44
言語 C++14
(gcc 12.3.0 + boost 1.83.0)
結果
AC  
実行時間 242 ms / 2,000 ms
コード長 2,304 bytes
コンパイル時間 1,579 ms
コンパイル使用メモリ 167,752 KB
実行使用メモリ 5,056 KB
最終ジャッジ日時 2023-09-01 22:23:47
合計ジャッジ時間 2,986 ms
ジャッジサーバーID
(参考情報)
judge12 / judge16
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 1 ms
4,380 KB
testcase_01 AC 2 ms
4,380 KB
testcase_02 AC 5 ms
4,868 KB
testcase_03 AC 5 ms
5,056 KB
testcase_04 AC 4 ms
4,920 KB
testcase_05 AC 4 ms
4,860 KB
testcase_06 AC 5 ms
4,924 KB
testcase_07 AC 5 ms
4,988 KB
testcase_08 AC 5 ms
4,380 KB
testcase_09 AC 4 ms
4,380 KB
testcase_10 AC 5 ms
4,380 KB
testcase_11 AC 5 ms
4,924 KB
testcase_12 AC 5 ms
4,864 KB
testcase_13 AC 5 ms
4,876 KB
testcase_14 AC 5 ms
4,872 KB
testcase_15 AC 5 ms
4,380 KB
testcase_16 AC 5 ms
4,380 KB
testcase_17 AC 242 ms
4,376 KB
testcase_18 AC 9 ms
4,376 KB
testcase_19 AC 5 ms
4,876 KB
testcase_20 AC 7 ms
5,056 KB
testcase_21 AC 7 ms
4,376 KB
testcase_22 AC 4 ms
4,376 KB
testcase_23 AC 5 ms
4,376 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

  #include <bits/stdc++.h> 
using namespace std;
using ll =long long;
#define all(v) v.begin(),v.end()
 #define rep(i,a,b) for(int i=a;i<b;i++)
#define rrep(i,a,b) for(int i=a;i>=b;i--)

ll INF=2e18;
vector<int> Z_algorithm(string S) {
	int c = 0, n = S.size();
	//接頭辞の長さを保存する配列を返す。
	//i = 1からやるとする。
	//Z[1]には赤下線が存在しないので、「溢れるor共通部分がない」のところにまずいく。
	//実装上、上のような挙動をしてもらうため、Z[0]=n;は[1, n - 1]まで計算が終わった後に入れる。
	//cは、赤下線の左端の位置。
	vector<int> Z(n, 0);
	for (int i = 1; i < n; i++) {
		int l = i - c;
		//今着目してる部分が赤下線の左端から何個分離れているかをlに入れる。
		if (i + Z[l] < c + Z[c]) {
			//この条件を満たすのは、「青下線が赤下線に収まる」。
			//この時、すでに計算されてるなのでそれを流用する。
			Z[i] = Z[l];
		}
		else {
			//この条件を満たすのは、「赤下線から青下線が溢れる」or「赤下線と青下線の共通部分がない」。
			int j = max(0, c + Z[c] - i);
			//c + Z[c] - i > 0の時、これは「溢れる」が該当する。
			//溢れてるのなら、収まる分は計算せずに、溢れた分(j番目から)だけ愚直に突き合わせればよい。
			//そもそも共通部分がないならば、全部突き合わせる。この時、式からj = 0;となるとわかる。

			//愚直に突き合せてる部分
			while (i + j < n && S[j] == S[i + j])j++;
			
			Z[i] = j;
			//今の見てるiで、赤下線に完全に含まれなくなったので、今のiを赤下線の左端として、次のiをまた計算する。
			c = i;
		}
	}

	//最後にこれを忘れずに
	Z[0] = n;
	return Z;
}


void solve() {
ll N;cin>>N;
string S;cin>>S;
auto vec=Z_algorithm(S);
ll ans=0;

for(ll i=1;i<N;i++) {
  ll f=i;
  ll b=N-i;

  if(vec[i]<f&&vec[i]<b) {
    if(S[vec[i]]<S[i+vec[i]]) ans++;
  }
  
  else if(vec[i]<b) {
    if(vec[i]>=f) ans++;
  }
  
  else {
    if(vec[i]>f) ans++;
  }
  
}

cout<<ans<<endl;


}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  ll t;cin>>t;
  for(ll i=0;i<t;i++) {
    solve();
  }

}


  
0