zoukankan      html  css  js  c++  java
  • 【洛谷7114】[NOIP2020] 字符串匹配(Z函数)

    点此看题面

    • 给定一个长度为(n)的字符串(s)
    • 问有多少组种非空字符串(A,B,C),满足(s=(AB)^kC),且(A)中出现次数为奇数的字符个数小于等于(C)中的个数。
    • 数据组数(le5,nle2^{20})

    暴力做法

    考虑我们去枚举循环节(AB),枚举循环次数(k),暴力哈希判断是否可行。

    这样的复杂度应该是(O(Tn(ln n+26)))的,刚好被卡掉。

    一个简单的小优化

    首先我们考虑一个小优化,把复杂度中的(26)去掉。

    (x=k\%2),显然偶数个循环节中所有字符出现次数必然都是偶数,它们并不会对奇偶性造成任何影响。

    然后考虑当(x=0)的时候,(C)中奇数字符个数其实就是整个原串中奇数字符个数。

    (x=1)的时候,(C)中奇数字符个数就是当前后缀奇数字符个数,由于这个值每次只会修改(1),我们可以动态维护它。

    这样一来,我们的核心问题就是如何去掉(ln n)了。

    (Z)函数

    可以详见这篇博客:扩展 KMP(Z 函数)学习笔记

    众所周知,如果(i)是长度为(len)的子串([1,len])的循环节,充要条件就是子串([1,len-i])([i+1,len])完全相同。

    发现这等价于第(i+1)个后缀与原串的(LCP)(即(Z(i+1)))大于等于(len-i)

    那么可行的循环次数实际上就是(lfloorfrac{min{Z(i+1),n-i-1}}i floor+1)(注意,要取(min)是因为(C)不能为空),其中一半(k)为奇数,一半(k)为偶数。

    这样一来就能(O(1))计算了。

    代码:(O(Tn))

    #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 1048576
    using namespace std;
    int n,a[30],b[30],g[30];char s[N+5];
    int Z[N+5];I void GetZ()//预处理Z函数
    {
    	RI i,id,Mx=0;for(Z[1]=n,i=2;i<=n;i+Z[i]-1>Mx&&(Mx=i+Z[id=i]-1),++i)
    		{Z[i]=i<=Mx?min(Z[i-id+1],Mx-i+1):0;W(i+Z[i]<=n&&s[i+Z[i]]==s[1+Z[i]]) ++Z[i];}
    }
    int main()
    {
    	RI Tt,i,p,q,o,u,v,k;long long ans;scanf("%d",&Tt);W(Tt--)
    	{
    		for(scanf("%s",s+1),n=strlen(s+1),GetZ(),i=1;i<=26;++i) a[i]=b[i]=g[i]=0;//清空
    		for(p=q=o=u=v=0,i=1;i<=n;++i) (b[s[i]&31]^=1)?(++o,++q):(--o,--q);//统计整个串奇数字符个数
    		for(ans=0,i=1;i^n;++i) (b[s[i]&31]^=1)?(u+=g[++q]):(u-=g[q--]),//更新当前后缀中奇数字符个数,同时维护基数情况下合法A的个数
    			i>1&&(k=min(Z[i+1],n-i-1)/i+1,ans+=1LL*(k+1>>1)*u+1LL*(k>>1)*v),//计算答案
    			++g[(a[s[i]&31]^=1)?++p:--p],p<=q&&++u,p<=o&&++v;//加入一个可能的A,更新两种情况合法A的个数
    		printf("%lld
    ",ans);
    	}return 0;
    }
    
  • 相关阅读:
    InputStream,String相互转化
    HttpGet
    MySQL重复数据
    JS获取地址栏参数的方法
    Java解析采集模块
    按键精灵多机型定时秒杀综合版提交脚本
    按键精灵手机版监控像素变换点击脚本
    按键精灵手机版定时点击脚本
    按键精灵获取系统时间定时点击
    window时间服务器 国内可用
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu7114.html
Copyright © 2011-2022 走看看