2868. 子串分值
作者:互联网
题目链接
2868. 子串分值
对于一个字符串 \(S\) ,我们定义 \(S\) 的分值 \(f(S)\) 为 \(S\) 中恰好出现一次的字符个数。
例如 \(f(" a b a ")=1 , f(" a b c ")=3, f(" a a a ")=0\) 。
现在给定一个字符串 \(S[0 \ldots n-1]\) (长度为 \(n\) ),请你计算对于所有 \(S\) 的非空子串 \(S[i \ldots j](0 \leq i \leq j<n), f(S[i \ldots j])\) 的和是多少。
输入格式
输入一行包含一个由小写字母组成的字符串 \(S\) 。
输出格式
输出一个整数表示答案。
数据范围
对于 \(20 \%\) 的评测用例, \(1 \leq n \leq 10\) ;
对于 \(40 \%\) 的评测用例, \(1 \leq n \leq 100\) ;
对于 \(50 \%\) 的评测用例, \(1 \leq n \leq 1000\) ;
对于 \(60 \%\) 的评测用例, \(1 \leq n \leq 10000\) ;
对于所有评测用例, \(1 \leq n \leq 100000\) 。
输入样例:
ababc
输出样例:
21
样例说明
所有子串 \(f\) 值如下:
a 1
ab 2
aba 1
abab 0
ababc 1
b 1
ba 2
bab 1
babc 2
a 1
ab 2
abc 3
b 1
bc 2
c 1
解题思路
思维
考虑每一位对答案的贡献,先复制上一位对答案的贡献,针对上一位加入当前字符后产生的贡献:当这一位作为单个字符时,其产生的贡献为当前位与前面出现该字符的距离,如果前一位产生的贡献中有当前字符,则当前字符到前一位字符的距离产生的贡献不变,同时要减去与当前字符相同的前一位产生的贡献,同时如果前一位的前面不止一个当前字符,要加上与当前字符相同的前前位的贡献以消除之前减去的贡献
- 时间复杂度:\(O(n)\)
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define help {cin.tie(NULL);cout.tie(NULL);}
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
typedef pair<LL,LL> PLL;
template <typename T> bool chkMax(T &x,T y){return (x<y?x=y,1:0);}
template <typename T> bool chkMin(T &x,T y){return (x>y?x=y,1:0);}
template <typename T> inline void read(T &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();
}
while(s>='0'&&s<='9'){x+=x*10+(s^48),s=getchar();
}
x*=f;
}
string s;
int p[26],lp[26],cnt[26];
int main()
{
cin>>s;
int n=s.size();
s=' '+s;
LL res=0;
int lst=0;
for(int i=1;i<=n;i++)
{
int t=s[i]-'a';
lst+=i-p[t];
if(p[t])lst=lst-p[t]+lp[t];
res+=lst;
lp[t]=p[t];
p[t]=i;
}
cout<<res;
return 0;
}
标签:子串,字符,评测,leq,2868,分值,贡献,用例,int 来源: https://www.cnblogs.com/zyyun/p/16027383.html