题目:
对于一个字符串 S, 我们定义 S 的分值 f(S) 为 S 中恰好出现一次的字符个数。例如 (′′aba′′)=1,(′′abc′′)=3,(′′aaaa′′)=0。现在给定一个字符串S[0..n−1](长度为 n),请你计算对于所有 S 的非空 子串 S[i..j](0≤i≤j<n),f(S[i..j]) 的和是多少。
方法一(50分)
题目要求的是累加母串的每一个子串中不重复的字符个数
STEP ONE:
那么自然先想到要枚举子串
有两种枚举的方法(时间复杂度都是O(n^2) )
枚举长度+左端点--》右端点
for(int len=2;len<=leng;len++)
for(int l=0;l+len-1<leng;l++)
int r=l+len-1;
枚举左端点+右端点--》长度
for(int i=0;i<leng;i++)
{.....
for(int j=i+1;j<leng;j++)
{...}
}
STEP TWO
计算累加
以第二种枚举方式为例:
第一重循环在于把以确定是枚举第i个元素为首的子序列,第二重循环是进行以第i个元素为首的子序列的枚举,这样两重循环可以保证所有子序列都被枚举到,不重不漏
具体实施:1.由于子序列是不断在延长的,所以后面的数量也依赖于之前的数量
2. 每新增一个字符,先判断这个字符是否曾经在已有的子序列中出现过(vector存放已有的字母,find判断是否出现过)
2.1 如果没有,那么这一个子序列的cnt要比上一个多一个,所以cnt++,并累加到ans中,把 这个字符存进去
2.2 如果出现过:则要考虑是第一次还是第n(n>=2)次,一次并且前一个的cnt大于0,那么就把cnt--,多次的话则不必操作cnt,直接存入vector就可以了(count函数)
if(find(now[i].begin(),now[i].end(),str[j])==now[i].end())
if(count(now[i].begin(),now[i].end(),str[j])==1)
完整代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e5+10;
bool vis[N];
char str[N];
vector<char>now[N];
long long ans;
int main()
{
cin>>str;
int leng=strlen(str);
for(int i=0;i<leng;i++)
{
long long cnt=1;
now[i].push_back(str[i]);
ans+=cnt;
for(int j=i+1;j<leng;j++)
{
if(find(now[i].begin(),now[i].end(),str[j])==now[i].end())
{
cnt++;
ans+=cnt;
now[i].push_back(str[j]);
}
else
{
if(cnt>0&&count(now[i].begin(),now[i].end(),str[j])==1)cnt--;
now[i].push_back(str[j]);
ans+=cnt;
}
}
}
cout<<ans;
}
方法二(100分)
step one:对于每一个字母i,找出它是唯一的字符串范围,也就是找出在它之前的出现相同字符的位置,记为pre[i],在他之后出现的相同字符的位置,记为ne[i]
step two:根据组合数的乘法原理,在这段字符串中包含字母i的子串数目为(i-pre[i])*(ne[i]-i)
(以上可以各用一次循环,从后到前,从前到后)
step three:循环每一个字母,累加
拿样例举例
代码展示:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1e6+10;
char str[N];//输入str+1,方便pre初始化
int pre[N];//用来存放在这个字母之前相同字母出现的位置,初始化为0
int idx[N];//为了下次找pre做准备
int ne[N];//用来存放在这个字母之后相同字母出现的位置,初始化为len+1
int iidx[N];//为了找ne方便
long long int ans;
int main()
{
cin>>str+1;
int len=strlen(str+1);//len还是实实在在的长度,所以下面循环到=len
for(int i=1;i<=len;i++)//求pre,顺便初始化iidx
{
pre[i]=idx[str[i]];
idx[str[i]]=i;
iidx[str[i]]=len+1;
}
for(int i=len;i>=1;i--)//求ne
{
ne[i]=iidx[str[i]];
iidx[str[i]]=i;
}
for(int i=1;i<=len;i++)
{
ans+=(i-pre[i])*(ne[i]-i);
}
cout<<ans;
}