zoukankan      html  css  js  c++  java
  • 【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统计答案
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    [LeetCode] Power of Three 判断3的次方数
    [LeetCode] 322. Coin Change 硬币找零
    [LeetCode] 321. Create Maximum Number 创建最大数
    ITK 3.20.1 VS2010 Configuration 配置
    VTK 5.10.1 VS2010 Configuration 配置
    FLTK 1.3.3 MinGW 4.9.1 Configuration 配置
    FLTK 1.1.10 VS2010 Configuration 配置
    Inheritance, Association, Aggregation, and Composition 类的继承,关联,聚合和组合的区别
    [LeetCode] Bulb Switcher 灯泡开关
    [LeetCode] Maximum Product of Word Lengths 单词长度的最大积
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT4163.html
Copyright © 2011-2022 走看看