魔力
### Description
数据范围:\(n<=10^5\)
Solution
脑抽选手选择回家种田qwq
没啥难度的一题。。丢上来是为了记录一下场上的弱智操作。。
首先想一下如果只有两种字符,那么出现次数我们可以求个差,然后从左往右扫,枚举右端点,如果当前前缀和之差的结果为\(x\),那么\(ans\)就应该加上前面的满足前缀和之差\(=x\)的位置的数量
字符比较多的情况下相邻的求差然后哈希压一下就好了
然而场上我的瓶颈在于。。认为这样并不能保证到每个字符都出现== 但实际上冷静一点想一下会发现由于查的是“前面的”满足条件的位置,所以可以保证到至少有一个字符出现了一次,而我们求的又是所有的字符出现次数相同的情况,那么自然不会出现有的字符没有出现这种情况==
然后我因为这个弱智操作写了一个线段树去拿字符集小的情况的部分分。。好结局qwq
Code
//Force是暴力
//T2是十分弱智地写了个线段树去拿部分分
//T3是正解
//为自己的智商风暴哭泣qwq
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int N=1e5+10,C=52,MOD=1e9+7;
char s[N];
int Cnt[C],rec[C];
int n,m,ans;
int change(char ch){
if ('a'<=ch&&ch<='z') return ch-'a';
else return ch-'A'+26;
}
int plu(int x,int y){return (1LL*x+y)-(1LL*x+y>=MOD?MOD:0);}
namespace Force{
int cnt[N][C];
bool check(int l,int r){
int x,tmp=cnt[r][rec[1]]-cnt[l-1][rec[1]];
if (tmp==0) return 0;
for (int i=2;i<=rec[0];++i)
if (cnt[r][rec[i]]-cnt[l-1][rec[i]]!=tmp) return 0;
return 1;
}
void solve(){
for (int i=1;i<=n;++i){
for (int j=0;j<C;++j) cnt[i][j]=cnt[i-1][j];
++cnt[i][change(s[i])];
}
ans=0;
for (int i=1;i<=n;++i){
for (int j=i+rec[0]-1;j<=n;j+=rec[0])
if (check(i,j))
ans=plu(ans,1);
}
}
}
namespace Seg{
const int N=::N*2*20;
int ch[N][2],sum[N],rt[::N];
int n,tot;
void init(int _n){n=_n; tot=0;}
int newnode(int pre){
++tot;
ch[tot][0]=ch[pre][0]; ch[tot][1]=ch[pre][1];
sum[tot]=sum[pre]; return tot;
}
void _modify(int pre,int &x,int d,int lx,int rx,int delta){
x=newnode(pre);
sum[x]+=delta;
if (lx==rx) return;
int mid=lx+rx>>1;
if (d<=mid) _modify(ch[pre][0],ch[x][0],d,lx,mid,delta);
else _modify(ch[pre][1],ch[x][1],d,mid+1,rx,delta);
}
void modify(int pre,int x,int d,int delta){++pre; ++x; _modify(rt[pre],rt[x],d,0,n,delta);}
int _query(int x,int d,int lx,int rx){
if (lx==rx) return sum[x];
int mid=lx+rx>>1;
if (d<=mid) return _query(ch[x][0],d,lx,mid);
else return _query(ch[x][1],d,mid+1,rx);
}
int query(int x,int d){++x;return _query(rt[x],d,0,n);}
}
void debug(int x){
for (int i=0;i<=n*2;++i) printf("%d ",Seg::query(x,i)); printf("\n");
}
namespace T2{
int sum[N*2],cnt[N][2];
int loc[2],pre[N];
void solve(){
int c;
loc[0]=0; loc[1]=0;
for (int i=1;i<=n;++i){
c=change(s[i])==rec[1];
for (int j=0;j<2;++j) cnt[i][j]=cnt[i-1][j];
++cnt[i][c];
pre[i]=loc[c^1];
loc[c]=i;
}
Seg::init(2*n);
Seg::modify(-1,0,0+n,1);
ans=0;
for (int i=1;i<=n;++i){
if (pre[i])
ans=plu(ans,Seg::query(pre[i]-1,cnt[i][0]-cnt[i][1]+n));
Seg::modify(i-1,i,cnt[i][0]-cnt[i][1]+n,1);
}
}
}
namespace T3{
const int Hs=19260817;//just for debuging
ull pw[C];
map<ull,int> sum;
int cnt[N][C];
int loc[C],pre[N][C];
ull get_val(int x){
ull ret=0;
int nxt;
for (int i=1;i<::rec[0];++i){
ret=ret*Hs+(cnt[x][::rec[i]]-cnt[x][::rec[i+1]]+n);
}
ret=ret*Hs+(cnt[x][::rec[rec[0]]]-cnt[x][::rec[1]]+n);
return ret;
}
void solve(){
int c,p;
ull val;
memset(loc,0,sizeof(loc));
for (int i=1;i<=n;++i){
c=change(s[i]);
for (int j=1;j<=rec[0];++j)
cnt[i][rec[j]]=cnt[i-1][rec[j]],pre[i][rec[j]]=pre[i-1][rec[j]];
++cnt[i][c];
pre[i][c]=i;
}
val=get_val(0);
sum[val]=1;
for (int i=1;i<=n;++i){
val=get_val(i);
ans=plu(ans,sum[val]);
sum[i]=sum[i-1];
++sum[val];
}
}
}
void prework(){
int c;
rec[0]=0;
for (int i=1;i<=n;++i){
c=change(s[i]);
if (Cnt[c]==0) rec[++rec[0]]=c;
++Cnt[c];
}
sort(rec+1,rec+1+rec[0]);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&n);
scanf("%s",s+1);
prework();
if (rec[0]==2)
T2::solve();
else if (n<=2000)
Force::solve();
else
T3::solve();
printf("%d\n",ans);
}