kuangbin 專題二十三:二分 尺取 單調棧佇列 String

Qyif發表於2020-11-01

題目連線:
傳送門

#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N = 30;
const int M = 1000010;

int t, k, cnt[N];
char str[M]; 

int main() {
	scanf("%d", &t);
	while(t--) {
		//輸入資料
		scanf("%s", str);
		scanf("%d", &k);
		//初始化資料
		memset(cnt, 0, sizeof cnt);
		int n = strlen(str), f = 0;
		ll ans = 0;
		//尺取
		for(int i = 0, j = 0; i < n; i++) {
			//判斷當前尺子上是否存在k個不同的字元
			while(j < n && f < k) {
				//當前字元未出現過則f++
				if(cnt[str[j] - 'a'] == 0) f++;
				cnt[str[j] - 'a']++;
				j++;
			}
			//如果f的個數符合要求
			if(f == k) {
				ans += n - j + 1;
			}
			//尺頭移出時數量要減一
			cnt[str[i] - 'a']--;
			//若該字元在尺子中再不出現則f--
			if(cnt[str[i] - 'a'] == 0) f--;
		}
		printf("%lld\n", ans);
	}
	return 0;
}

這道題可以用尺取法來做
接下來講講尺取的方法:
首先設定幾個變數,f代表當前尺子上的不同類字元的個數,cnt陣列記錄當某字元出現過多少次,
然後講講思路:尺子頭尾都指向第一個字元,每次將尺尾往後移動,每次移動時判斷當前,當前尺尾的字母在尺子中是否出現過,如果未出現則讓 f 的數量加一,同時當前字元在尺子上出現的數量要加一,尺尾往後移,直到 f 的數量等於要求的k為止。此時前一段滿足,則後面的字元加入該串中也能形成符合條件的串,因此ans += n - j + 1。當記錄完後,把尺頭往前,往前移動時,要把對應的字元尺子中刪去,即尺頭對應的字元的數量要減一。同時如果這個尺子上再沒有同種字元的話,就要讓 f 減一。以此類推。
最後注意ans要開long long

相關文章