zoukankan      html  css  js  c++  java
  • JZOJ6682. 【2020.06.04省选模拟】串在哪(string)

    Description

    在这里插入图片描述
    n<=105,Bi<=2e5n<=10^5,sum|Bi|<=2e5

    • 原题GDSOI2019 D2 T3 Novel

    Solution

    • 相当巧妙的AC自动机上的DP。
    • 首先对于这一类分数规划的问题一般都要二分答案,然后化一下式子变成Wl,rmidlen>=0W_{l,r}-mid*len>=0,也就是长度每多1,贡献都要减去midmid,求最大值。这样子就不需要记录起点了。
    • 显然建一个AC自动机,直接设状态f[i]f[i]表示AC自动机上以ii为结尾的字符串最大的Wl,rmidlenW_{l,r}-mid*len
    • 既然是在AC自动机上DP,那么考虑下一个字符的节点是xx,那么考虑f[x]f[x]的值,首先不难想到它直接从f[fail[x]]f[fail[x]]转移过来,但是这样还有一段起点不会考虑到。
    • 因此再设一个状态g[x]g[x]表示从fail[x]fail[x]前为起点,到xx的最大值,那么f[x]=max(g[x],f[fail[x]])f[x]=max(g[x],f[fail[x]])
    • 考虑g[x]g[x]的转移,设yyxx的父亲,那么可以发现在yy跳fail的过程中,这些节点fail[y],fail[fail[y]],fail[...]fail[y],fail[fail[y]],fail[...]gg所覆盖的起点区间刚好是不相交的,所以直接考虑将这些gg转移过来,再加上以当前位置为末尾的字符串的贡献sum[fail[x]]midsum[fail[x]]-mid
    • 这样一直跳到一个yy使得yy有儿子zzxx匹配,即fail[x]=zfail[x]=z
    • 这就是一个跳fail的过程,并且所有加进去的gg都包括fail[x]fail[x],所以时间复杂度和正确性有了保证。
    • 注意没有计算到整个串xx的贡献,单独补上。
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 300005
    #define ll long long 
    #define db double 
    using namespace std;
    
    int n,q,m,p,i,j,k,x,y,z;
    int id,tot,tr[maxn][26],fail[maxn],dep[maxn];
    db f[maxn],g[maxn],sum[maxn],h[maxn];
    
    int t,w,d[maxn],fa[maxn];
    void prepare(){
    	for(i=0;i<26;i++) tr[0][i]=1;
    	t=0,w=1,d[1]=1;
    	while (t<w){
    		x=d[++t];
    		for(i=0;i<26;i++) if (tr[x][i]){
    			y=tr[x][i],dep[y]=dep[x]+1,d[++w]=y;
    			for(z=fail[x];!tr[z][i]&&z;z=fail[z]);
    			fail[y]=tr[z][i];
    			sum[y]+=sum[fail[y]],h[y]=h[x]+sum[y];
    		}
    	}
    }
    
    int check(db mid){
    	t=0,w=1,d[1]=1;
    	for(i=1;i<=tot;i++) f[i]=g[i]=-1e15;
    	while (t<w){
    		x=d[++t];
    		for(i=0;i<26;i++) if (tr[x][i]){
    			y=tr[x][i];
    			g[y]=max(g[y],g[x]-mid+sum[fail[y]]);
    			for(z=fail[x];!tr[z][i]&&z;z=fail[z])
    				g[y]=max(g[y],g[z]-mid+sum[fail[y]]);
    			g[y]=max(g[y],h[y]-mid*dep[y]);
    			f[y]=max(f[fail[y]],g[y]);
    			d[++w]=y;
    		}
    	}
    	db mx=-1e15;
    	for(x=id;x;x=fa[x]) 
    		mx=max(mx,f[x]);
    	return mx>=0;
    }
    
    int main(){
    	freopen("string.in","r",stdin);
    	freopen("string.out","w",stdout);
    	char ch=getchar();
    	tot=x=1;
    	while (ch>='a'&&ch<='z') {
    		if (!tr[x][ch-'a']) tr[x][ch-'a']=++tot;
    		fa[tr[x][ch-'a']]=x,x=tr[x][ch-'a'],ch=getchar();
    	} id=x;
    	scanf("%d",&m);
    	while (m--){
    		for(ch=getchar();ch<'a'||ch>'z';ch=getchar());
    		x=1; 
    		while (ch>='a'&&ch<='z') {
    			if (!tr[x][ch-'a']) tr[x][ch-'a']=++tot;
    			fa[tr[x][ch-'a']]=x,x=tr[x][ch-'a'],ch=getchar();
    		}
    		scanf("%d",&k),sum[x]+=k;
    	}
    	prepare();
    	db L=0,R=1e10,mid,E=1e-6;
    	while (L+E<R){
    		mid=(L+R)/2;
    		if (check(mid)) L=mid;
    		else R=mid;
    	}
    	printf("%.4lf",R);
    }
    
  • 相关阅读:
    jQuery 基础一 样式篇
    javaJavaScript DOM
    linux 实用命令
    Linux下修改.bash_profile 文件改变PATH变量的值
    java 字符串截取的方法
    Telnet命令参考手册
    linux下dubbo调试 ---telnet命令
    【Spring Task】定时任务详解实例-@Scheduled
    Spring定时任务的几种实现
    SQL之case when then用法
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090875.html
Copyright © 2011-2022 走看看