题目:http://codeforces.com/contest/519/problem/D
题意:在字符串里面找出有多少子串除首尾字符,其权值的和为0,且首尾字符相同。
分析:将字符和前缀和插入hash表,然后查询字符前缀和,注意去重。
代码:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
#define MOD 300007
#define MAXN 1000000
struct node
{
LL per_sum;
char ch;
LL count;
int next;
};
struct Hash
{
int Table[MOD],cnt;
node List[MAXN];
void Clear()
{
cnt=0;
for(int i=0;i<MOD;i++)
Table[i]=-1;
}
void Insert(LL sum,char ch)
{
LL hash=sum+ch;
if(hash<0)
hash=-hash;
hash=hash%MOD;
LL temp=hash;
temp=Table[hash];
while(temp!=-1)
{
if(List[temp].per_sum==sum && List[temp].ch==ch)
{
List[temp].count++;
return ;
}
temp=List[temp].next;
}
List[cnt].ch=ch;
List[cnt].per_sum=sum;
List[cnt].count=1;
List[cnt].next=Table[hash];
Table[hash]=cnt;
cnt++;
}
LL Search(LL sum,char ch)
{
LL hash=sum+ch;
if(hash<0)
hash=-hash;
hash=hash%MOD;
hash=Table[hash];
while(hash!=-1)
{
if(List[hash].ch==ch && List[hash].per_sum==sum)
return List[hash].count;
hash=List[hash].next;
}
return 0;
}
}H;
char str[100010];
LL sum[1000010];
int main()
{
H.Clear();
int weight[30],i,j,k;
LL ans=0;
for(i=0;i<26;i++)
scanf("%d",&weight[i]);
scanf("%s",str);
sum[0]=weight[str[0]-'a'];
for(i=1;str[i]!='\0';i++)
sum[i]=sum[i-1]+weight[str[i]-'a'];
H.Insert(sum[0],str[0]);
for(i=1;str[i]!='\0';i++)
{
ans+=H.Search(sum[i-1],str[i]);
H.Insert(sum[i],str[i]);
}
cout<<ans<<'\n';
return 0;
}
map版,更清爽,不过慢一点
#include <iostream>
#include <map>
#include <cstdio>
using namespace std;
typedef long long LL;
char str[100010];
int main()
{
map <LL,int> mp[26];
LL s[26],i,j,ans=0,sum=0;
for(i=0;i<26;i++)
cin>>s[i];
scanf("%s",str);
for(i=0;str[i];i++)
{
ans+=mp[str[i]-'a'][sum];
sum+=s[str[i]-'a'];
mp[str[i]-'a'][sum]++;
}
cout<<ans<<"\n";
return 0;
}