贡献法(C++)
贡献法的核心思想: 不要一个个子串去算“有多少种字符”,而是反过来想——每个字符能“贡献”给多少个子串
1.子串分值
#include<bits/stdc++.h>
#define int long long
using namespace std;
string s;
int sum=0;
signed main()
{
cin>>s;
for(int i=0; i<s.size(); i++) //计算贡献度:字母的贡献度 = (左边的步数 + 1) * (右边的步数 + 1)
{
int left=0,right=0;
for(int j=i-1; j>=0 && s[j]!=s[i]; j--) //计算左边的步数
{
left++;
}
for(int j=i+1; j<s.size() && s[j]!=s[i]; j++)
{
right++;
}
sum+=(left+1)*(right+1);
}
cout<<sum<<endl;
return 0;
}
2.子串分值和
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
char s[N];
int pos[27]; //记录该字符上一次出现的位置
signed main()
{
cin>>s+1; //索引1开始完整读取
int n=strlen(s+1);
int res=0;
for(int i=1; i<=n; i++)
{
int t=s[i]-'a';
res+=(int)(i-pos[t])*(n-i+1); //n-i+1加一是为了包括自己
pos[t]=i; //只有最左边的那个会被计入贡献
}
cout<<res<<endl;
return 0;
}