• BZOJ3238: [Ahoi2013]差异


    BZOJ3238: [Ahoi2013]差异

    Description

    Input

    一行,一个字符串S

    Output

    一行,一个整数,表示所求值

    Sample Input

    cacao

    Sample Output

    54

    HINT

    2<=N<=500000,S由小写英文字母组成


    题解Here!
    看到$LCP(T_i,T_j)$就想起了后缀数组。
    先把式子变个形:
    题目要求:$$Ans=sum_{i=1}^{n-1}sum_{j=i+1}^n(len(T_i)+len(T_j)-2 imes LCP(T_i,T_j))$$
    即:$$Ans=sum_{i=1}^{n-1}sum_{j=i+1}^n(len(T_i)+len(T_j))-2 imes sum_{i=1}^{n-1}sum_{j=i+1}^nLCP(T_i,T_j)$$
    设$Ans=S-2T$
    我们知道:$T_i=suffix(i)$。
    那么:$len(T_i)=n-i+1$
    所以:$$S=sum_{i=1}^{n-1}sum_{j=i+1}^n(n-i+1+n-j+1)$$
    即:$$S=sum_{i=1}^{n-1}sum_{j=i+1}^n(i+j)=frac{n(n-1)(n+1)}{2}$$
    所以问题就变成了怎么求$T$。
    对于每一个$height[i]$,若$height[i-1]<=height[i]$,那么$height[i-1]$能取到的值$height[i]$都能取到。
    若$height[i-1]>height[i]$,这部分的$LCP$长度就是$height[i]$。
    所以我们用类似$DP$的思想,用一个单调栈维护前面距$i$最近且小于等于$height[i]$的元素,记为$p$。
    则转移方程为:$$f[i]=f[p]+(i-p) imes height[i]$$
    于是我们就有:$$T=sum_{i=1}^nf[i]$$
    然后就可以随便跑了。
    附代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<stack>
    #include<cstring>
    #define MAXN 500010
    using namespace std;
    int n;
    long long sum,f[MAXN];
    char str[MAXN];
    int top=0,sa[MAXN],rk[MAXN],tax[MAXN],tp[MAXN],height[MAXN];
    struct node{
    	int val,id;
    };
    stack<node> s;
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    void radixsort(){
    	for(int i=0;i<=top;i++)tax[i]=0;
    	for(int i=1;i<=n;i++)tax[rk[i]]++;
    	for(int i=1;i<=top;i++)tax[i]+=tax[i-1];
    	for(int i=n;i>=1;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void suffixsort(){
    	top=30;
    	for(int i=1;i<=n;i++){
    		rk[i]=str[i]-'a'+1;
    		tp[i]=i;
    	}
    	radixsort();
    	for(int w=1,p=0;p<n;top=p,w<<=1){
    		p=0;
    		for(int i=1;i<=w;i++)tp[++p]=n-w+i;
    		for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
    		radixsort();
    		swap(rk,tp);
    		rk[sa[1]]=p=1;
    		for(int i=2;i<=n;i++)
    		rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
    	}
    }
    void getheight(){
    	for(int i=1,j,k=0;i<=n;i++){
    		if(k)k--;
    		j=sa[rk[i]-1];
    		while(str[i+k]==str[j+k])k++;
    		height[rk[i]]=k;
    	}
    }
    void work(){
    	int pos=0;
    	long long ans=0;
    	for(int i=1;i<=n;i++){
    		int p=pos;
    		while(!s.empty()&&s.top().val>height[i])s.pop();
    		if(!s.empty())p=s.top().id;
    		f[i]=f[p]+(i-p)*height[i];
    		ans+=f[i];
    		if(!height[i])pos=i;
    		s.push((node){height[i],i});
    	}
    	printf("%lld
    ",sum-ans*2LL);
    }
    void init(){
    	scanf("%s",str+1);
    	n=strlen(str+1);
    	suffixsort();
    	getheight();
    	sum=1LL*n*(n-1)*(n+1)/2;
    }
    int main(){
    	init();
    	work();
        return 0;
    }
    

    强力解法:$SAM$

    (坑,未填。。。)

  • 相关阅读:
    Android开发——弹性滑动的两种实现方式
    管理知识和解决信息爆炸问题的4种方法
    京东金融的业务版图
    京东金融的业务版图
    虚幻引擎4艺术大师
    Android开发——View滑动的三种实现方式
    Android开发之Path类使用详解,自绘各种各样的图形!
    C# Dictionary的遍历理解
    我想走全产业链发展路线
    Androd安全——混淆技术完全解析
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9543573.html
Copyright © 2020-2023  润新知