arc099F

题目大意

题解

哈希,表示成Σai*p^i(i可以为负),设Si表示后缀哈希值,sumi表示前缀>+1<-1的和

那么区间[l,r]满足当且仅当(S_l-S_r*p^{sum_r-sum_{l-1}}=S_1),移项后乘上p^sum(l-1),枚举lmap统计

要写双哈希

code

#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define mod 1000000007
#define Mod 1000000005
#define ll long long
//#define file
using namespace std;

ll p[250001],P[250001],pp[250001],PP[250001],hs[250001],Hs[250001],s,S,p1,p2,p3,p4,ans;
int sum[250001],n,i,j,k,l;
char st[250001];
map<pair<int,int>,int> mp;
map<pair<int,int>,int> :: iterator I;

ll qpower(ll a,int b) {ll ans=1; while (b) {if (b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;} return ans;}
ll Pow(int t) {return (t>=0)?p[t]:P[-t];}
ll Pow2(int t) {return (t>=0)?pp[t]:PP[-t];}

int main()
{
	#ifdef file
	freopen("arc099f.in","r",stdin);
	#endif
	
	scanf("%d",&n);
	scanf("%s",st+1);
	p1=123456789,p2=qpower(p1,Mod);
	p3=114514191,p4=qpower(p3,Mod);
	p[0]=P[0]=pp[0]=PP[0]=1;
	fo(i,1,n) p[i]=p[i-1]*p1%mod,P[i]=P[i-1]*p2%mod,pp[i]=pp[i-1]*p3%mod,PP[i]=PP[i-1]*p4%mod;
	
	fd(i,n,1)
	{
		switch (st[i])
		{
			case '>':{sum[i]=1,s=s*p1%mod;break;}
			case '<':{sum[i]=-1,s=s*p2%mod;break;}
			case '+':{s=(s+1)%mod;break;}
			case '-':{s=(s-1)%mod;break;}
		}
		s=(s+mod)%mod;
		hs[i]=s;
	}
	s=0;
	fd(i,n,1)
	{
		switch (st[i])
		{
			case '>':{sum[i]=1,s=s*p3%mod;break;}
			case '<':{sum[i]=-1,s=s*p4%mod;break;}
			case '+':{s=(s+1)%mod;break;}
			case '-':{s=(s-1)%mod;break;}
		}
		s=(s+mod)%mod;
		Hs[i]=s;
	}
	fo(i,1,n) sum[i]+=sum[i-1];
	
	mp[pair<int,int>(0,0)]=1;
	fd(i,n,1)
	{
		s=((hs[i]-hs[1])*Pow(sum[i-1])%mod+mod)%mod;
		S=((Hs[i]-Hs[1])*Pow2(sum[i-1])%mod+mod)%mod;
		I=mp.find(pair<int,int>(s,S));
		if (I!=mp.end())
		ans+=I->second;
		++mp[pair<int,int>(hs[i]*Pow(sum[i-1])%mod,Hs[i]*Pow2(sum[i-1])%mod)];
	}
	printf("%lld
",ans);
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}
原文地址:https://www.cnblogs.com/gmh77/p/13678369.html