zoukankan      html  css  js  c++  java
  • NOIP2020 T2字符串匹配

    一个字符串,把它写成((AB)^iC)的形式,并且要求(f(A)le f(C)),其中(f(S))表示字符串(S)中出现了奇数次的字符。统计合法四元组((A,B,C,i))(A,B,C)不为空串,(i>0))的个数。

    (nle 2^{20})


    这就是NOIP题吗,爱了爱了。

    当场写了个(O(nln n+26n))的做法,用了双哈希常数有点大。而且我哈希的时候是直接用循环串的性质判的,而不是对于每个循环节分别判,这导致我甚至没有意识到可以break

    听说有人直接unsigned long long哈希过了?

    可以发现性质:如果((AB)^iC)合法,那么((AB)^{i-2}C)一定合法。

    枚举(AB)长度(len),分别考虑(AB(AB)^{2i}C)(ABAB(AB)^{2i}C)的情况。以前者为例。

    一种做法:还是双哈希,然后二分出最大的(i)。这一部分的时间是(sum lgfrac{n}{i}=nlg n-sum lg i),估算一下(int lg i=nlg n-n),然后发现时间复杂度是(O(n))

    另一种做法:写个exkmp,问(LCP(s_{len+1dots n},s_{1dots n})),就可以得到最大的(i)

    搞完这些这题基本做完了。

    还需要查一下(f(C))固定时合法的(f(A))有多少个。由于常数小,可以直接(O(26n))搞过去;也可以(O(nlg 26))。或者还可以发现:你想要查的(f(C))的变化量是(O(1))的,于是维护个桶和一个值,当(len)增大时对这个值改一下即可,那时间就是(O(n))


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N (1<<20|5)
    #define ll long long
    int n;
    char s[N];
    int ex[N];
    void init(){
    	ex[1]=n;
    	int p=0,mx=0;
    	for (int i=2;i<n;++i){
    		ex[i]=0;
    		if (i<=mx)
    			ex[i]=min(mx-i+1,ex[i-p+1]);
    		while (s[1+ex[i]]==s[i+ex[i]] && i+ex[i]<n)
    			++ex[i];
    		if (i+ex[i]-1>mx)
    			mx=i+ex[i]-1,p=i;
    	}
    	ex[n+1]=0;
    }
    int buc[27],cnt;
    int f[N];
    int g[27];
    int main(){
    	freopen("in.txt","r",stdin);
    //	freopen("out.txt","w",stdout);
    	int T;
    	scanf("%d",&T);
    	while (T--){
    		scanf("%s",s+1);
    		n=strlen(s+1);
    		init();
    		cnt=0,memset(buc,0,sizeof buc);
    		f[n+1]=0;
    		for (int i=n;i>=1;--i){
    			cnt-=(buc[s[i]-'a']&1);
    			cnt+=(++buc[s[i]-'a']&1);
    			f[i]=cnt;
    		}
    //		for (int i=1;i<=n;++i)	
    //			printf("%d ",f[i]);
    //		printf("
    ");
    		memset(g,0,sizeof g);
    		cnt=0,memset(buc,0,sizeof buc);
    		ll ans=0;
    		for (int i=1;i<n;++i){
    			ll tmp=ans;
    			ans+=(ll)g[f[i+1]]*(ex[i+1]/(2*i)+1);
    			if (i+i+1<=n && ex[i+1]>=i)
    				ans+=(ll)g[f[i+i+1]]*(ex[i+i+1]/(2*i)+1);
    //			printf("%lld
    ",ans-tmp);
    			cnt-=(buc[s[i]-'a']&1);
    			cnt+=(++buc[s[i]-'a']&1);
    			for (int j=cnt;j<=26;++j)
    				g[j]++;
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux中使用dd制作文件的.img
    python正则表达式
    使用@property
    Win10添加删除虚拟打印机方法
    jenkins权限
    RedHat7.2下Jenkins的安装配置
    jenkins忘记管理员账号密码的补救方法
    RHEL软件安装
    docker 常用指令(RHLE)
    /var/run/yum.pid 已被锁定,PID 为 4242 的另一个程序正在运行
  • 原文地址:https://www.cnblogs.com/jz-597/p/14140605.html
Copyright © 2011-2022 走看看