zoukankan      html  css  js  c++  java
  • [BZOJ4480] JSOI2013 快乐的jyy

    问题背景

    JYY在JSOI有很多很多的好朋友,比如PUPPY,KFC还有PUPPUP。因为有了这么多的好朋友,所以JYY每天都很快乐。某天,JYY发现好朋友之间关系的好坏和名字有很大的关系,比如PUPPY和PUPPUP的关系就特别好,但是和KFC的关系就很一般。JYY苦思冥想终于发现了其中的规律,现在JYY想知道两个朋友之间关系的好坏,你能帮助JYY么?

    问题描述

    给定两个字符串A和B,表示JYY的两个朋友的名字。我们用A(i,j)表示A字符串中从第i个字母到第j个字母所组成的子串。同样的,我们也可以定义B(x,y)。JYY发现两个朋友关系的紧密程度,等于同时满足如下条件的四元组(i,j,x,y)的个数:

    1:1<=i<=j<=|A|

    2:1<=x<=y<=|B|

    3:A(i,j)=B(x,y)

    4:A(i,j)是回文串

    这里表示字符串A的长度。

    JYY希望你帮助他计算出这两个朋友之间关系的紧密程度。

    输入格式

    数据包行两行由大写字母组成的字符串A和B
    1≤|A|,|B|≤50000。

    输出格式

    包含一行一个整数,表示紧密程度,也就是满足要求的4元组个数

    样例输入

    PUPPY
    PUPPUP

    样例输出

    17

    链接

    BZOJ

    解析

    在这道题中,我们需要统计第二个字符串中的回文串在第一个串中的出现情况。这种问题,我们可以用回文自动机来实现。对第一个串建立回文自动机,然后在建好的fail树上做一次子树和统计每一种回文串出现的次数,记为(sum_i)。然后用第二个字符串上的每一个位置在回文自动机上匹配,记录每个点的匹配次数,然后同样在做一次子树和记录每个回文串被匹配的次数,记为(cnt_i)。最后答案就是:

    [sum_{i=1}^n sum_i imes cnt_i ]

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 50002
    using namespace std;
    struct PAM{
    	int son[26],fail,len,sum,cnt;
    }t[N];
    char a[N],b[N];
    int n,m,i,num,last;
    void insert(int p,int x)
    {
    	int cur=last;
    	while(a[p-1-t[cur].len]!=a[p]) cur=t[cur].fail;
    	if(!t[cur].son[x]){
    		num++;
    		int tmp=t[cur].fail;
    		while(a[p-1-t[tmp].len]!=a[p]) tmp=t[tmp].fail;
    		t[num].len=t[cur].len+2;
    		t[num].fail=t[tmp].son[x];
    		t[cur].son[x]=num;
    	}
    	t[t[cur].son[x]].sum++;
    	last=t[cur].son[x];
    }
    void find(int p,int x)
    {
    	int cur=last;
    	while(cur!=1&&(b[p-1-t[cur].len]!=b[p]||!t[cur].son[x])) cur=t[cur].fail;
    	if(b[p-1-t[cur].len]==b[p]&&t[cur].son[x]) last=t[cur].son[x],t[last].cnt++;
    	else last=1;
    }
    int main()
    {
    	scanf("%s%s",a+1,b+1);
    	n=strlen(a+1);m=strlen(b+1);
    	num=last=1;
    	t[0].fail=t[1].fail=1;
    	t[1].len=-1;
    	for(i=1;i<=n;i++) insert(i,a[i]-'A');
    	for(i=num;i>=1;i--) t[t[i].fail].sum+=t[i].sum;
    	last=0;
    	for(i=1;i<=m;i++) find(i,b[i]-'A');
    	for(i=num;i>=1;i--) t[t[i].fail].cnt+=t[i].cnt;
    	long long ans=0;
    	for(i=2;i<=num;i++) ans+=1LL*t[i].sum*t[i].cnt;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    加载声音的过程
    onkeyup,onkeydown和onkeypress
    加载着色器的异常

    3
    1
    1
    java总结
    环路
    own address as source address
  • 原文地址:https://www.cnblogs.com/LSlzf/p/12300628.html
Copyright © 2011-2022 走看看