码迷,mamicode.com
首页 > 其他好文 > 详细

2018ECfinal J. Philosophical Balance

时间:2019-03-05 15:37:01      阅读:292      评论:0      收藏:0      [点我收藏+]

标签:getc   \n   char   line   pac   bit   fast   ons   man   

2018ECfinal J. Philosophical Balance

题目大意:

给出一个字符串 \(s\) ,你需要给每一个 \(i\) 一个 \([0,1]\) 之间的权值 \(k_i\) ,且满足 \(\sum k_i=1\) 。并且最小化
\[ \max_{i=1}^n(\sum_{j=1}^nlcp(suf(s,j),suf(s,i))\times k_j) \]
先证明一个比较简单的结论,把 \(s\) 的后缀树建出来,考虑后缀树的每一个子树,如果子树的根是 \(s\) 的一个后缀,那么分配到这个子树里面的所有权值必然全部分配到根上。

假设这个子树 \(u\) 里第 \(i\) 个节点分配了 \(k_i\) 的权值,那么对于根的贡献是 \(\sum{k_i}\times len_{u}\) ,考虑对其它点的贡献是每一个权值乘在其某个祖先的 \(len\) 上,由于 \(len\) 向上递减,根的贡献固定,那么显然全部放在根上最优。

\(f(u)\) 为后缀树上 \(u\) 节点所在子树内部的答案,当 \(u\) 是后缀节点的时候 \(f(u)=len(fa_u)-len(u)\) 。否则只需要合并每一个儿子的 \(f(v)\)

考虑儿子与儿子之间是独立的,所有不同儿子之间的贡献都是 \(u\) ,只需要最后把 \(u\) 到父亲的边加上去就可以,考虑最优解的一定是每个值相等,感性理解可以得到式子:
\[ \sum {k_i} = 1 \f_1k_1 = f_2k_2=\dots= f_mk_m= x \\sum \frac{x}{f_i}=1 \\frac{1}{x} = \sum \frac{1}{f_i} \x = \frac{1}{\sum \frac{1}{f_i}} \]
\(\mathcal O(n)\) 算一算就做完了。

/*program by mangoyang*/
#pragma GCC optimize("Ofast", "inline")
#include <bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
    int ch = 0, f = 0; x = 0;
    for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
    for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    if(f) x = -x;
}
#define double long double
const int N = 500005;
vector<int> vec[N];
char s[N];
ll all, val[N]; int n, cnt;
namespace SAM{
    vector<int> g[N];
    int ch[N][26], pos[N], fa[N], len[N], size = 1, tail = 1;
    inline int newnode(int x){ return len[++size] = x, size; }
    inline void ins(int c, int x){
        int p = tail, np = newnode(len[p] + 1); pos[np] = x;
        for(; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
        if(!p) return (void) (fa[np] = 1, tail = np);
        int q = ch[p][c];
        if(len[q] == len[p] + 1) fa[np] = q;
        else{
            int nq = newnode(len[p] + 1);
            fa[nq] = fa[q], fa[q] = fa[np] = nq;
            for(int i = 0; i < 26; i++) ch[nq][i] = ch[q][i];
            for(; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
        }tail = np;
    }
    inline void addedge(){
        for(int i = 2; i <= size; i++) g[fa[i]].push_back(i);
    }
    inline double gao(int u, int d){
        if(pos[u]) return d;
        double res = 0;
        for(int i = 0; i < (int) g[u].size(); i++)
            res += 1.0 / gao(g[u][i], len[g[u][i]] - len[u]);
        return 1.0 / res + d;
    }
}
int main(){
    int T; read(T);
    while(T--){
        for(int i = 1; i <= SAM::size; i++){
            SAM::g[i].clear();
            SAM::pos[i] = SAM::fa[i] = SAM::len[i] = 0;
            memset(SAM::ch[i], 0, sizeof(SAM::ch[i]));
        }
        SAM::tail = SAM::size = 1;
        scanf("%s", s + 1); n = strlen(s + 1);
        for(int i = n; i; i--) SAM::ins(s[i] - 'a', i);
        SAM::addedge();
        printf("%.10Lf\n", SAM::gao(1, 0));
    }
}

2018ECfinal J. Philosophical Balance

标签:getc   \n   char   line   pac   bit   fast   ons   man   

原文地址:https://www.cnblogs.com/mangoyang/p/10476902.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!