Hướng dẫn cho Kaninho tập đếm với xâu
Chỉ sử dụng khi thực sự cần thiết như một cách tôn trọng tác giả và người viết hướng dẫn này.
Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.
Chép code từ bài hướng dẫn để nộp bài là hành vi có thể dẫn đến khóa tài khoản.
Authors:
Hint 1: Với mỗi \(i\), hãy tìm \(j\) lớn nhất mà \(S[i..j]\) thỏa mãn điều kiện đề bài.
Hint 2: Có thể tìm được \(j\) bằng cách nào?
Hint 3: Làm sao để kiểm tra \(S[i..j]\) thỏa mãn điều kiện?
Lời giải:
Chúng ta sẽ dùng kỹ thuật 2 con trỏ để xử lý bài toán này. Hai con trỏ \(i, j\) sẽ lưu vị trí mà \(S[i..j]\) thỏa mãn điều kiện. Trong quá trình di chuyển hai con trỏ, cần lưu mảng \(cnt[a..z]\) là số lần xuất hiện của mỗi ký tự trong xâu con hiện tại.
Đô phức tạp: \(O(n)\)
Bình luận
Có thể sử dụng tìm kiếm nhị phân đc k vậy?
/**
contest: https://codeforces.com/group/FxFJrQUeaZ/contest/527641
problem: https://codeforces.com/group/FxFJrQUeaZ/contest/527641/problem/F
rank: https://codeforces.com/group/FxFJrQUeaZ/contest/527641/standings/groupmates/true
profile(me): https://codeforces.com/profile/ThanhSteve2k11 (k1ngch0m-imissmath-nguyenquangthanh)
ideone: https://ideone.com/uaGOsi
date/school/country: (SUN/06/OCT/2024-ChuVanAnSecondarySchool-DANANG-VIETNAM)
**/
include <bits/stdc++.h>
using namespace std;
define int long long
define double long double
define FAST ios_base::sync_with_stdio(false),cin.tie(0),cout.tie(0)
define endl "\n"
define sz(s) (int)s.size()
define gl(s) string s;getline(cin,s)
define cin(n) int n;cin >> n
define __lcm(a,b) a/__gcd(a,b)*b
define fset(x) fixed << setprecision(x)
define MOD (int)1e9+7
define maxn (int)1e5+1
void FREOPEN(){freopen(".inp","r",stdin);freopen(".out","w",stdout);}
int cnt[255+1], pref[255+1][maxn];
bool ok(int l,int r,int k) {
// kt doan l->r co ok ko
// tinh nhanh so luong tung chu cai & kt chung co vuot qua k ko
for(int i='a';i<='z';i++) {
// dem so luong kitu i trong doan l->r
int cnt = pref[i][r] - pref[i][l-1];
if (cnt>k) return false;
}
return true;
}
void k1ngch0m() {
string s; cin >> s;
int SZ = sz(s);
s = '1'+s;// dich vi tri xau s ve 1
cin(k);
for(int i='a';i<='z';i++) {
// mang cong don cho kitu i
// pref[i][j] dung cho kitu da tinh so luong kitu i tu 1->j
for(int j=1;j<=SZ;j++) {
int x;
if (s[j]==i) x=1;
else x=0;
pref[i][j] = pref[i][j-1]+x;
}
}
// dem so cap i j sao cho tu i->j ko co kitu nao xuat hien qua k lan
int ans=0;
for(int i=1;i<=SZ;i++) {
int l=i, r=SZ, mid, pos=i-1;
while(l<=r) {
mid = (l+r)/2;
// kt doan tu i->mid co ok ko
if (ok(i,mid,k)) pos=mid, l=mid+1;
else r = mid-1;
}
ans+=pos-i+1;
}
cout << ans << endl;
// C2: binary_search + prefix_sum
}
signed main() {
/FREOPEN();/ FAST;
int test=1; cin >> test;
while (test--) k1ngch0m();
}
đây nha
được nha.
với mỗi chỉ số i bạn tknp thằng j xa nhất thoả mãn sao cho:
f[j]['a'] - f[i-1]['a'] <= k
f[j]['b'] - f[i-1]['b'] <= k
f[j]['c'] - f[i-1]['c'] <= k
...
f[j]['z'] - f[i-1]['z'] <= k
rồi áp dụng công thức tính số lượng đoạn con là được