前缀和和后缀和
1.Problem - 1791D - Codeforces
定义函数 f()f() 表示字符串 x 中不同字符的数量。
现给定一个字符串 S,将它分割为两个字符串 a,b。求出:max(f()+f())max(f(a)+f(b))。
我们可以搞一个前缀和 a 和一个后缀和 b,分别表示 f(S1∼Si) 和 f(Si∼Sn)。
然后枚举分界点即可。

1 #include <bits/stdc++.h> 2 #define re register 3 4 using namespace std; 5 6 const int N = 2e5 + 10,M = 230; 7 int T,n; 8 int arr[N],brr[N]; 9 string s; 10 bool vis[M]; 11 12 int main(){ 13 cin >> T; 14 while (T--){ 15 int ans = 0; 16 memset(arr,0,sizeof(arr)); 17 memset(brr,0,sizeof(brr)); 18 memset(vis,false,sizeof(vis)); 19 cin >> n >> s; 20 s = ' ' + s; 21 for (re int i = 1;i <= n;i++){//前缀和 22 if (!vis[s[i]]){ 23 arr[i] = arr[i - 1] + 1; 24 vis[s[i]] = true; 25 } 26 else arr[i] = arr[i - 1]; 27 } 28 memset(vis,false,sizeof(vis)); 29 for (re int i = n;i;i--){//后缀和 30 if (!vis[s[i]]){ 31 brr[i] = brr[i + 1] + 1; 32 vis[s[i]] = true; 33 } 34 else brr[i] = brr[i + 1]; 35 } 36 for (re int i = 0;i <= n;i++) ans = max(ans,arr[i] + brr[i + 1]);//选出 max 37 printf("%d\n",ans); 38 } 39 return 0; 40 }
2.Problem - B - Codeforces 利用pair分别存储数组的值和下标,然后对值进行排序,对每一个a[i],最多有i - 1个
我们可以通过前缀和来根据题目的条件来判断,只有当前前缀和大于该a[i]时才满足条件,指针++,否则输出当前前缀和
的个数 - 1。

1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define cy cout << "Yes" << endl 5 #define cn cout << "No" << endl 6 7 const int N = 1e6 + 10,inf = 1e9; 8 const int mode = 1e9 + 7; 9 ll j,k,n,m,t; 10 ll a[N],p[N],id[N],res[N]; 11 12 int main(){ 13 cin>>t; 14 while(t--){ 15 cin>>n; 16 vector<pair<ll,ll> > v; 17 for(ll i=1;i<=n;i++){ 18 cin>>k; 19 v.push_back({k,i}); 20 res[i]=0; 21 } 22 sort(v.begin(),v.end()); n=0; 23 24 for(auto [x,y]:v){ 25 n++; 26 a[n]=x; 27 id[n]=y; 28 } 29 30 for(ll i=1;i<=n;i++)p[i]=p[i-1]+a[i]; 31 j=1; 32 for(ll i=1;i<=n;i++){ 33 j=max(j,i); 34 while(j<n){ 35 if(a[j+1]>p[j]){ 36 break; 37 } 38 j++; 39 } 40 res[id[i]]=j-1; 41 } 42 for(ll i=1;i<=n;i++){ 43 cout<<res[i]<<' '; 44 } 45 cout<<'\n'; 46 } 47 }
3.Problem - 1352E - Codeforces
某一段连续的和想到用前缀和,我们可以用双指针来表示两个前缀和的差值。
将这个数组里的数都放进一个桶里。然后枚举区间的左右端点,答案累加为这个区间和的数的个数。有两个点需要注意:
-
判断区间和是否超过n(因为区间里的数都在n以内),否则要么RE,要么炸空间。
-
一次累加桶里的某个数后,要记得将桶里的这个数的个数清00,否则会重复算。代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define endl '\n' 4 #define ll long long 5 #define cy cout << "YES" << endl 6 #define cn cout << "NO" << endl 7 int _,n,m; 8 const int N = 1e3 + 10,inf = 1e9; 9 const int mod = 1e9 + 7; 10 int a[N],s[N],t[N]; 11 12 int main() 13 { 14 cin >> _; 15 while(_ -- ) 16 { 17 memset(s, 0, sizeof s); 18 memset(t, 0, sizeof t); 19 cin >> n; 20 for (int i = 1; i <= n; i ++ ) cin >> a[i],s[i] = s[i - 1] + a[i],t[a[i]] ++; 21 22 int ans = 0; 23 for (int i = 0; i <= n; i ++ ){ 24 for (int j = i + 2; j <= n; j ++ ) 25 if(s[j] - s[i] <= n) 26 { 27 ans += t[s[j] - s[i]]; 28 t[s[j] - s[i]] = 0; 29 } 30 else break; 31 } 32 cout << ans << endl; 33 } 34 }
4.Problem - 1692G - Codeforces 这道题目转换一下题意就是当a[i] < 2 * a[i + 1]的时候满足条件
我们可以把满足这两个条件的a[i]转换为b[i] = 1,否则b[i] = 0,然后构造出来一个长度为n -1 的数组,在这个数组中我们只需要找到
长度k和由k个1组成的子序列,然后动态滑动窗口维护这个区间的值,当其等于k的时候,满足条件的区间数量 + 1

1 #include<bits/stdc++.h> 2 using namespace std; 3 #define endl '\n' 4 #define ll long long 5 #define cy cout << "YES" << endl 6 #define cn cout << "NO" << endl 7 #define c1 cout << -1 << endl 8 9 int _,n,k; 10 const int N = 2e5 + 10,inf = 1e9; 11 const int mod = 1e9 + 7; 12 int a[N]; 13 14 15 int main() 16 { 17 cin >> _; 18 while(_ -- ){ 19 cin >> n >> k; 20 for (int i = 1; i <= n; i ++ ) cin >> a[i]; 21 22 int b[n]; 23 for (int i = 1; i < n; i ++ ){ //将满足条件的a[i]转换为b[i] 24 if(a[i] < 2 * a[i + 1]) b[i] = 1; 25 else b[i] = 0; 26 } 27 28 int ans = 0; 29 for (int i = 1; i <= k; i ++ ) 30 ans += b[i]; 31 32 int res = 0; 33 if(ans == k) res ++; 34 for (int i = k + 1; i < n; i ++ ){ //滑动窗口动态维护长度为K的区间,然后判断这个区间内的值是否为k 35 ans += b[i]; 36 ans -= b[i - k]; 37 if(ans == k) res ++; 38 } 39 40 cout << res << endl; 41 } 42 return 0; 43 }