• 【AT4163】[ARC099D] Eating Symbols Hard(哈希)


    点此看题面

    • 有一个初始全为(0)的数组一个初始在(0)的指针。
    • 给定一个长度为(n)的操作串,有四种操作符:"<"表示将指针左移一位,">"表示将指针右移一位,"+"表示将指针对应位置加(1),"-"表示将指针对应位置减(1)
    • 求有多少子串,使得执行其中操作得到的数组和整串相同。
    • (nle2.5 imes10^5)

    哈希

    我们设(f_i(x))表示执行了前(i)位得到数组的生成函数(sum_{k=-infty}^{+infty}a_kx^k)(g_i(x))表示执行了前(i)位指针指向位置(p_i)对应的(x^{p_i})

    考虑一个操作符的转移。

    如果是"<"或">",则(f_i(x)=f_{i-1}(x))(g_i(x)=g_i(x) imes x^{mp1})

    如果是"+"或"-",则(f_i(x)=f_{i-1}(x)pm g_i(x))(g_i(x)=g_{i-1}(x))

    然后我们只要任选两个(x)代入,就成为双哈希了。

    答案的计算

    考虑一段([L,R])操作得到的生成函数应该是:

    [frac{f_R(x)-f_{L-1}(x)}{g_{l-1}(x)} ]

    现在它需要等于(f_n(x)),也就是说:

    [f_n(x)=frac{f_R(x)-f_{L-1}(x)}{g_{l-1}(x)}Leftrightarrow f_n(x) imes g_{l-1}(x)+f_{L-1}(x)=f_R(x) ]

    因此我们从后往前枚举(L)(map)中维护好所有的(f_R(x)),然后询问有多少个$ f_n(x) imes g_{l-1}(x)+f_{L-1}(x)$计入答案即可。

    代码:(O(nlogn))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 250000
    #define S1 324682339
    #define S2 456789001
    #define X 998244353
    using namespace std;
    int n;char s[N+5];I int QP(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
    struct Hash
    {
    	int x,y;I Hash() {x=y=0;}I Hash(CI a):x(a),y(a){}I Hash(CI a,CI b):x(a),y(b){}
    	I Hash operator + (Con Hash& o) Con {return Hash((x+o.x)%X,(y+o.y)%X);}
    	I Hash operator - (Con Hash& o) Con {return Hash((x-o.x+X)%X,(y-o.y+X)%X);}
    	I Hash operator * (Con Hash& o) Con {return Hash(1LL*x*o.x%X,1LL*y*o.y%X);}
    	I bool operator < (Con Hash& o) Con {return x^o.x?x<o.x:y<o.y;}
    }seed,f[N+5],g[N+5],sd(S1,S2),isd(QP(S1,X-2),QP(S2,X-2));map<Hash,int> p;
    int main()
    {
    	RI i;for(scanf("%d%s",&n,s+1),g[0]=i=1;i<=n;++i) switch(s[i])//按运算符分类讨论
    	{
    		case '+':f[i]=f[i-1]+(g[i]=g[i-1]);break;case '-':f[i]=f[i-1]-(g[i]=g[i-1]);break;
    		case '<':f[i]=f[i-1],g[i]=g[i-1]*isd;break;case '>':f[i]=f[i-1],g[i]=g[i-1]*sd;break;
    	}
    	long long t=0;for(i=n;i;--i) ++p[f[i]],t+=p[g[i-1]*f[n]+f[i-1]];return printf("%lld
    ",t),0;//从后往前枚举L统计答案
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    CodeForces
    网络流
    poj 2185
    树的分治学习
    数位DP
    URAL 1969. Hong Kong Tram
    hdu 4759 Poker Shuffle
    hdu3712 Detector Placement
    分块思想
    莫比乌斯反演
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT4163.html
Copyright © 2020-2023  润新知