zoukankan      html  css  js  c++  java
  • 背单词

    https://loj.ac/problem/2012

    题目描述

      给出(n)个字符串,他们有一定顺序,并且满足(设第(i)个字符串为(s)):

      (①)若这(n)个字符串中有(s)的后缀,并且顺序在(i)之后,代价为(n*n)

      (②)若这(n)个字符串中不存在(s)的后缀,代价为(i)

      (③)若这(n)个字符串中存在(s)的后缀在(i)之前,并且假设最近的后缀位置为(j),代价为(i-j)

    思路

      吐槽一下出题人的语文水平,看了半天没看出顺序是自己定的,后缀指的是(n)个字符串中存在的所有后缀。不过题目理清楚就比较简单了,首先第一条规则没有任何意义,因为如果按照(②、③)规则,显然可以存在并且代价小于(n*n),所以我们只用考虑把一个字符串的后缀填在它前面。接下来就是解决统计答案的问题。由于字符串和字符串的后缀存在图的关系,我们可以从后缀到字符串建一条有向边。所以我们可以(dfs)建成的图,从(0)点开始。所以对于一个位置(u),我们考虑对所有的子树的(size),进行一种排序,使父亲和子树的差最小。我们可以用贪心,显然(size)小的要排在后面,这样可以使总和最小。

      由于我们有一个虚根(0),连向其他所有无后缀的节点,所以必定可以通过(dfs)访问所有节点。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int MAXN=3e5+10;
    int val[MAXN],nxt[MAXN<<1],to[MAXN<<1],head[MAXN];
    int ch[510005][26],tot,idx,siz[MAXN],fa[MAXN],ed[MAXN];
    char s[MAXN];
    void add_edge(int x,int y)
    {
        nxt[++tot]=head[x];
        head[x]=tot;
        to[tot]=y;
    }
    ll ans=0;
    vector<int>a[MAXN];
    void dfs(int u,int fa)
    {
        siz[u]=1;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
    //        if(v==fa)continue ;
            dfs(v,u);
            siz[u]+=siz[v];
            a[u].push_back(siz[v]);
        }
        sort(a[u].begin(),a[u].end());//从小到大排序可以正着统计答案
        ll s=0;
        for(int i=0;i<a[u].size();i++)
        {
            ans+=s+1;  //由于包括这个节点编号,所以要加1
            s+=a[u][i];
        }
    }
    int main() 
    {
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf(" %s",s);
            int u=0,len=strlen(s);
            for(int j=len-1;j>=0;j--)
            {
                int c=s[j]-'a';
                if(!ch[u][c])
                {
                    ch[u][c]=++idx;
                    fa[idx]=u;
                }
                u=ch[u][c];
            }
            val[i]=u;
            ed[u]=i;
        }
        for(int i=1;i<=n;i++)
        {
            int k=fa[val[i]];
            while(k&&!ed[k])k=fa[k];
            add_edge(ed[k],i);
        }
        dfs(0,0);
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Linux
    Monkey命令
    ADB命令
    DOS命令
    列表
    函数
    文件读写及实操项目
    Selenium2自动化——初体验
    新开淘宝店怎么提升信誉,是不是真的要刷钻?
    JSFL:导入根文件夹将所有图片添加库链接导出swf
  • 原文地址:https://www.cnblogs.com/fangbozhen/p/11788342.html
Copyright © 2011-2022 走看看