题目链接:点击查看
题目大意:给出一个字符串,在这个题目中的子序列定义为,出现次数必须是等差数列的序列,如:aaabb的其中一个子序列就是aab,其出现的位置是1 3 5,呈等差数列,现在问,在这个题目中出现次数最多的子序列,出现的次数是多少
题目分析:又是一道读完题后猜出正解,但因为实现一直WA的题目,其实读完题后,再参照样例,可以猜个差不多的结论,那就是对答案有贡献的子序列,长度不是 1 就是 2 ,因为自己举了几个例子后发现,如果存在一个长度大于 2 的子序列,那么其长度必定可以拆成长度为 1 的或者长度为 2 的,这样一来我们就发现等差数列的这个条件也就变成了烟雾弹,因为长度为 1 和长度为 2 的子序列无论如何组合,都肯定是等差数列
有了上面的猜想就不难实现了,长度为 1 的子序列就是统计一下每个字母出现的次数,取最多的那个字母就行了,而长度为二的子序列,我用了一种比较笨的方法,那就是直接暴力枚举两个字母,时间复杂度是 n * 26 * 26 ,不过也无伤大雅,枚举的这两个字母是不相同的,而相同的我们可以利用排列组合 C( mmax , 2 ) 计算得出,这里的 mmax 就是刚才求出的,出现次数最多的字母了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
char s[N];
LL cnt[N][26];//前缀和
int main()
{
//#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
//#endif
// ios::sync_with_stdio(false);
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1;i<=len;i++)
{
for(int j=0;j<26;j++)
cnt[i][j]=cnt[i-1][j];
cnt[i][s[i]-'a']++;
}
LL mmax=0;
for(int i=0;i<26;i++)
mmax=max(mmax,cnt[len][i]);
mmax=max(mmax,(mmax-1)*mmax/2);
for(int j=0;j<26;j++)
for(int k=0;k<26;k++)
{
if(j==k)
continue;
LL temp=0;
for(int i=1;i<=len;i++)
if(s[i]==char(k+'a'))
temp+=cnt[i][j];
mmax=max(mmax,temp);
}
printf("%lld\n",mmax);
return 0;
}