CF386C
题意
其实可以发现,我们先枚举右端点的话,对于不同的
什么意思呢?就是说,对于很多左端点来说,他们到右端点的子串
然后我们发现这个东西它具有单调性,可以进行二分,具体的,对于以右端点
然而过不去。
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
const int INF=3e5+5;
string s1;
int sum[INF][35],t[35];
int check(int l,int r) {
// cout<<l<<" "<<r<<" "<<"bomb\n";
int ans=0;
for (int i=0;i<26;i++)
if (sum[r][i]-sum[l-1][i]) ans++;
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>s1;int len=s1.size();s1=" "+s1;
for (int i=1;i<=len;i++) {
for (int j=0;j<26;j++)
sum[i][j]=sum[i-1][j]+((s1[i]-'a')==j);
}
for (int i=1;i<=len;i++) {
int j=i;
while (j>=1) {
int l=1,r=j,ans=-1,xx=check(j,i);
while (l<=r) {
int Mid=(l+r)>>1;
if (check(Mid,i)==xx) r=(ans=Mid)-1;
else l=Mid+1;
}
t[xx]+=j-ans+1;
j=ans-1;
// cout<<j<<" "<<ans<<" ??\n";
}
}
cout<<check(1,len)<<"\n";
for (int i=1;i<=26;i++)
if (t[i]) cout<<t[i]<<"\n";
return 0;
}
可惜,这里是
然后我们考虑如何优化这个过程,我们发现这个复杂度的瓶颈出在二分以及 check。
假如说我们以及知道了要记录的
考虑枚举这个
但是这题稍微有点烦,因为它双指针需要记录相同的数量。
如果仅仅跑的最后一个相同的,然后跑回来,那肯定会 TLE 起飞。
考虑用两个双指针,一个指向第一个,另外一个指向最后一个。
和莫队的想法一样,对于新出现的字符加到一个桶里面,然后就可以很快速的查询当前区间出现字符。
#include <iostream>
#include <cstdio>
#define int long long
using namespace std;
const int INF=3e5+5;
string s1;
int sum[INF][35],t[35],la[35],la1[35];
int check(int l,int r) {
// cout<<l<<" "<<r<<" "<<"bomb\n";
int ans=0;
for (int i=0;i<26;i++)
if (sum[r][i]-sum[l-1][i]) ans++;
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin>>s1;int len=s1.size();s1=" "+s1;
for (int i=1;i<=len;i++) {
for (int j=0;j<26;j++)
sum[i][j]=sum[i-1][j]+((s1[i]-'a')==j);
}
for (int i=1;i<=26;i++) {
int j1=0,j2=0,sum1=0,sum2=0;
for (int k=1;k<=len;k++) {
j1=max(j1,k-1);j2=max(j2,k-1);
while (j1+1<=len && sum1<=i) {
if (la[s1[j1+1]-'a']==0 && sum1==i) break;
la[s1[j1+1]-'a']++;
if (la[s1[j1+1]-'a']==1) sum1++;
j1++;
}
// if (sum1>i)
while (j2+1<=len && sum2<i) {
// if (la1[s1[j2+1]-'a']==0 && sum2==i-1) break;
la1[s1[j2+1]-'a']++;
if (la1[s1[j2+1]-'a']==1) sum2++;
j2++;
}
// cout<<k<<" "<<i<<" "<<j1<<" "<<j2<<" ?\n";
if (sum2==i && sum1==i) t[i]+=j1-j2+1;
la1[s1[k]-'a']--;
if (la1[s1[k]-'a']==0) sum2--;
////
la[s1[k]-'a']--;
if (la[s1[k]-'a']==0) sum1--;
}
}
cout<<check(1,len)<<"\n";
for (int i=1;i<=26;i++)
if (t[i]) cout<<t[i]<<"\n";
return 0;
}