2018-2019 ACM-ICPC, Asia East Continent Finals J. Philosophical … Balance

題面

題意

多組數據,每組數據給出一個長度爲n的字符串S,求maxij=1nlcp(i,j)kj\max_{i}{\sum_{j=1}^{n}lcp(i,j)*k_{j}}的最小值
其中kik_{i}由你定,但是要滿足i=1nki=1\sum_{i=1}^{n}k_{i}=1,且0<=ki<=10<=k_{i}<=1

做法

首先用後綴自動機對字符串的反串建出後綴樹,然後考慮計算在後綴樹中的每棵子樹怎麼分配k值。
對於一棵子樹,如果根節點u是後綴節點,則很顯然,如果這棵子樹到的k值之和爲x,那麼根節點的答案就是lcp(i,u)x\sum{lcp(i,u)*x},且lcp(i,u)=len[u]lcp(i,u)=len[u](先不考慮子樹外的串的貢獻),而且不難發現這是子樹中所有串中最大的。
如果根節點u不是後綴節點,那麼就要考慮將它的幾個子節點的子樹合併,我們已經遞歸求出了它的每棵子樹的kk,表示如果分配給這棵子樹xx,它的最小值將是kxk*x,爲了使所有子樹的最大值最小,從那什均衡的角度思考,最好讓它們都相等,如果分配給子樹v,a的權值,那麼它的貢獻就是
ak[v]a*k[v](內部貢獻)+(1a)len[u]+(1-a)*len[u](子樹之間的貢獻)
只要讓幾棵子樹的這個值相等即可。

代碼

#include<bits/stdc++.h>
#define db double
#define N 400100
using namespace std;

int T,n,tt,last;
char str[N];
db K[N];
struct Node
{
    int to[26],len,pa;
    bool bj;
}node[N<<1];
vector<int>to[N];

inline void add(int u)
{
    int p=last,np=++tt;
    last=np;
    node[np].len=node[p].len+1;
    for(;p&&!node[p].to[u];p=node[p].pa) node[p].to[u]=np;
    node[np].bj=1;
    if(!p)
    {
		node[np].pa=1;
		return;
    }
    int q=node[p].to[u];
    if(node[q].len==node[p].len+1)
    {
		node[np].pa=q;
		return;
    }
    int nq=++tt;
    node[nq].len=node[p].len+1;
    node[nq].pa=node[q].pa;
    memcpy(node[nq].to,node[q].to,sizeof(node[q].to));
    node[np].pa=node[q].pa=nq;
    for(;node[p].to[u]==q;p=node[p].pa) node[p].to[u]=nq;
}

void dfs(int now)
{
    if(node[now].bj)
    {
		K[now]=node[now].len;
		return;
    }
    int i,t,p;
    db sum=0;
    for(i=0;i<to[now].size();i++)
    {
		t=to[now][i];
		dfs(t);
		if(!i) sum+=1,p=t;
		else sum+=(K[p]-node[now].len)/(K[t]-node[now].len);
    }
    sum=1.0/sum;
    K[now]=(1-sum)*node[now].len+sum*K[p];
}

int main()
{
    int i,j;
    cin>>T;
    while(T--)
    {
		for(i=1;i<=tt;i++)
		{
		    to[i].clear();
		    node[i].pa=0;
		    node[i].len=0;
		    node[i].bj=0;
		    memset(node[i].to,0,sizeof(node[i].to));
		}
		tt=last=1;
		scanf("%s",str+1);
		n=strlen(str+1);
		reverse(str+1,str+n+1);
		for(i=1;i<=n;i++) add(str[i]-'a');
		for(i=2;i<=tt;i++) to[node[i].pa].push_back(i);
		dfs(1);
		printf("%.10f\n",K[1]);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章