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

    Description

    给定一张包含N个单词的表,每个单词有个价值W。要求从中选出一个子序列使得其
    中的每个单词是后一个单词的子串,最大化子序列中W的和。 
     

    Input

    第一行一个整数TEST,表示数据组数。 
    接下来TEST组数据,每组数据第一行为一个整数N。 
    接下来N行,每行为一个字符串和一个整数W。 

    Output

    TEST行,每行一个整数,表示W的和的最大值。 
     
     
    数据规模 
    设字符串的总长度为Len 
    30.的数据满足,TEST≤5,N≤500,Len≤10^4 
    100.的数据满足,TEST≤10,N≤20000,Len≤3*10^5

     
    题解
    首先对所有单词建AC自动机。另一个串是一个串的子串等价于这个串的任意前缀能够通过fail树到根的路径上走到另一个串。
    我们用f[i]表示一定选i这个串的最大收益。
    则f[i] = max(前缀能在fail树上走到的最大收益) + w[i]
    用线段树维护fail树的dfs序,区间修改,单点查询
    处理完每一个单词后直接在这个单词对应节点处加上f[i],相当于对于它的子树中所有点的答案取一个max
    时间复杂度O(LlogL)
     
      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 using namespace std;
      6 #define maxn 300020
      7 
      8 typedef long long ll;
      9 struct node{
     10     int ls,rs;
     11     ll mx,tag;
     12 }sgt[maxn * 2];
     13 struct node2{
     14     int next,to;
     15 }e[maxn * 2];
     16 int head[maxn],cnt;
     17 char ch[maxn];
     18 int T,n;
     19 int nxt[maxn][26],tot,dfstime,fa[maxn];
     20 int fail[maxn],rt,cur,l[maxn],r[maxn],rec[maxn],w[maxn];
     21 int q[maxn],tt,hh;
     22 ll f[maxn],ans;
     23 
     24 inline void clear(){
     25     for (int i = 1 ; i <= n ; i++) f[i] = 0;
     26     for (int i = 0 ; i <= tot ; i++) fail[i] = l[i] = r[i] = head[i] = fa[i] = rec[i] = 0;
     27     for (int i = 1 ; i <= tot ; i++) e[i].next = e[i].to = 0;
     28     for (int i = 0 ; i <= tot ; i++) memset(nxt[i],0,sizeof(nxt[i]));
     29     for (int i = 1 ; i <= cnt ; i++) sgt[i].tag = sgt[i].mx = 0 , sgt[i].ls = sgt[i].rs = 0;
     30     tot = cnt = dfstime = 0;
     31     ans = 0;
     32 }
     33 inline void adde(int x,int y){
     34     e[++cnt].to = y;
     35     e[cnt].next = head[x];
     36     head[x] = cnt;
     37 }
     38 inline void insert(int x){
     39     if ( !nxt[cur][x] ) nxt[cur][x] = ++tot , fa[tot] = cur;
     40     cur = nxt[cur][x];
     41 }
     42 void dfs(int x){
     43     if ( x ) l[x] = ++dfstime;
     44     for (int i = head[x] ; i ; i = e[i].next) dfs(e[i].to);
     45     r[x] = dfstime;
     46 }
     47 void build(int &x,int l,int r){
     48     x = ++cnt;
     49     if ( l == r ) return;
     50     int mid = (l + r) >> 1;
     51     build(sgt[x].ls,l,mid);
     52     build(sgt[x].rs,mid + 1,r);
     53 }
     54 void build_AC(){
     55     tt = hh = 0;
     56     for (int i = 0 ; i < 26 ; i++) if ( nxt[0][i] ) q[tt++] = nxt[0][i];
     57     while ( hh < tt ){
     58         int x = q[hh++];
     59         for (int i = 0 ; i < 26 ; i++){
     60             if ( nxt[x][i] ){
     61                 int p = fail[x];
     62                 while ( !nxt[p][i] && p ) p = fail[p];
     63                 fail[nxt[x][i]] = nxt[p][i]; //不是p
     64                 q[tt++] = nxt[x][i];
     65             }
     66         }
     67     }
     68     for (int i = 1 ; i <= tot ; i++) adde(fail[i],i);
     69     dfs(0);
     70     cnt = 0;
     71     build(rt,1,tot);
     72 }
     73 inline void update(int x){
     74     sgt[x].mx = max(sgt[sgt[x].ls].mx,sgt[sgt[x].rs].mx);
     75 }
     76 inline void add(int x,ll d){
     77     sgt[x].tag = max(sgt[x].tag,d);
     78     sgt[x].mx = max(sgt[x].mx,d);
     79 }
     80 inline void pushdown(int x){
     81     if ( sgt[x].tag != 0 ){
     82         add(sgt[x].ls,sgt[x].tag);
     83         add(sgt[x].rs,sgt[x].tag);
     84         sgt[x].tag = 0;
     85     }
     86 }
     87 void modify(int x,int l,int r,int ls,int rs,ll d){
     88     if ( ls <= l && rs >= r ){
     89         add(x,d);
     90         return;
     91     }
     92     pushdown(x);
     93     int mid = (l + r) >> 1;
     94     if ( ls <= mid ) modify(sgt[x].ls,l,mid,ls,rs,d);
     95     if ( rs > mid ) modify(sgt[x].rs,mid + 1,r,ls,rs,d);
     96     update(x);
     97 }
     98 ll query(int x,int l,int r,int id){
     99     if ( l == r ) return sgt[x].mx;
    100     pushdown(x);
    101     int mid = (l + r) >> 1;
    102     if ( id <= mid ) return query(sgt[x].ls,l,mid,id);
    103     return query(sgt[x].rs,mid + 1,r,id);
    104 }
    105 void Dodp(){
    106     for (int i = 1 ; i <= n ; i++){
    107         int p = rec[i];
    108         while ( p ){
    109             f[i] = max(f[i],query(rt,1,tot,l[p]));
    110             p = fa[p];
    111         }
    112         f[i] += w[i];
    113         f[i] = max(0ll,f[i]);
    114         modify(rt,1,tot,l[rec[i]],r[rec[i]],f[i]);
    115     }
    116     for (int i = 1 ; i <= n ; i++) ans = max(ans,f[i]);
    117 }
    118 int main(){
    119     freopen("input.txt","r",stdin);
    120     scanf("%d",&T);
    121     while ( T-- ){
    122         clear();
    123         scanf("%d",&n);
    124         for (int i = 1 ; i <= n ; i++){
    125             scanf("%s",ch) , scanf("%d",&w[i]);
    126             int l = strlen(ch);
    127             cur = 0;
    128             for (int j = 0 ; j < l ; j++){
    129                 insert(ch[j] - 'a');
    130             }
    131             rec[i] = cur;
    132         }
    133         build_AC();
    134         Dodp();
    135         printf("%lld
    ",ans);
    136     }
    137     return 0;
    138 }
     
     
  • 相关阅读:
    不依赖OFFICE组件实现带图片的EXCEL导出
    关于安装SQL的错误
    Web开发学习点滴(持续更新)
    窗体间传值汇总
    沈阳.NET俱乐部MSN群开张了。。。
    VoIP协议标准浅析
    名词解释
    创建和运行一个解决方案
    400电话为什么叫免费电话?
    XPO基础简化的属性语法:
  • 原文地址:https://www.cnblogs.com/zqq123/p/5505824.html
Copyright © 2011-2022 走看看