AcWing 4261. 孤独的照片 - AcWing 长度至少为3的子串(加一个判断分讨)
这里统计左右两边不同字母的方式还是很有意思的
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 10;
int l[N], r[N];
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
//还是利用乘法原理找连续子串,考虑每个独立的字母对答案的贡献!!!
for(int i = 0, h = 0, g = 0; i < s[i].size(); i ++ )
{
if(s[i] == 'H') l[i] = g, g = 0, h ++;
else l[i] = h, h = 0, g ++;
}
for(int i = s.size() - 1; i; i -- )
{
if(s[i] == 'H') r[i] = g, g = 0, h ++;
else r[i] = h, h = 0, g ++;
}
int ans = 0;
for(int i = 0; i < s.size(); i ++ )
{
if(l[i] + r[i] > 1) //长度至少为3
{
int cnt = (l[i] * r[i]) + max(0ll, l[i] - 1) + max(0ll, r[i] - 1); //两边都有牛,单选一边
ans += cnt;
}
}
cout << ans << endl;
}
signed main()
{
int t = 1;
while(t -- ) solve();
return 0;
}
P8715 [蓝桥杯 2020 省 AB2] 子串分值 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 无长度限制的子串,直接乘即可
转换一下思路:求s所有非空子串的中只出现一次的字母的个数 == 求只出现一次的独立字母对多少子串有贡献,即求有多少子串包含该独立字母
故要字母每个字母左边第一次出现的位置和右边第一次出现的位置
该题的记录方式也相当有趣!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 10;
int n;
int l[N], r[N];
//l[i]存的是第i个位置的字母上一次在左边出现的位置
//r[i]存的是第i个位置的字母上一次在右边出现的位置
void solve()
{
string s;
cin >> s;
int n = s.size();
map<char, int> p; //记录每个字母出现的位置
s = " " + s;
for(int i = 1; i <= n; i ++ )
{
l[i] = p[s[i]]; //赋值为上一次出现的位置
p[s[i]] = i;
}
for(int i = 'a'; i <= 'z'; i ++ )
p[i] = n + 1;
for(int i = n; i >= 1; i -- )
{
r[i] = p[s[i]];
p[s[i]] = i;
}
int ans = 0;
for(int i = 1; i <= n; i ++ )
ans += (i - l[i]) * (r[i] - i);
cout << ans << endl;
}
signed main()
{
int t = 1;
while(t -- ) solve();
return 0;
}