P8715 [蓝桥杯 2020 省 AB2] 子串分值
P8715 [蓝桥杯 2020 省 AB2] 子串分值 题解
思路一
这题首先想到的是暴力:
- 枚举区间左端点。
- 枚举区间右端点。
- 遍历当前所枚举的区间,累加仅出现一次的字母个数。
代码
时间复杂度为
思路二
我们不妨稍微优化一下,这里就不细说了,直接上代码。
代码
时间复杂度为
思路三(正解)
用乘法原理做。
操作步骤:
- 统计每个字母在只出现一次的情况下,能被多少子串所包含;
- 用
pre_i 记录第i 个字母上一次出现的位置,用nx_i 记录第i 个字母下一次出现的位置; - 那么往左最多能延伸到
pre_i+1 ,其到第i 个字母一共有i-pre_i 个字母; - 同理往右最多能延伸到
nx_i-1 ,其到第i 个字母一共有next_i-i 个字母; - 二者相乘,就是该字母被不同子串所包含的总次数;
代码
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N=100010,M=150; string s; ll pre[N],nx[N],idx[M]; int main(){ cin>>s; ll n=s.size(); s=' '+s; for(int i=1;i<=n;i++){ pre[i]=idx[s[i]]; idx[s[i]]=i; } for(int i=97;i<=122;i++){ idx[i]=n+1; } for(int i=n;i>=1;i--){ nx[i]=idx[s[i]]; idx[s[i]]=i; } ll ans=0; for(int i=1;i<=n;i++){ ans+=(i-pre[i])*(nx[i]-i); } cout<<ans; return 0; }
时间复杂度: