1. 程式人生 > >fzyjojP2963 -- [校內訓練20161227]疫情控制問題

fzyjojP2963 -- [校內訓練20161227]疫情控制問題

long lse trie pen line 完整 etc digi sdi

技術分享圖片

技術分享圖片

(題幹中的廢話已經劃去)

dp顯而易見

收益為負數的可以直接扔掉不管。不要一定更優

子串問題,考慮SAM

建立廣義SAM

嘗試匹配,匹配到的位置的parent樹祖先如果有完整的串,那麽可以從這個串轉移

考慮祖先不好考慮

不妨考慮i對j(i<j)的貢獻,就是子樹了

線段樹維護dfn序,區間對val取max

SAM學傻了

這個,由於是"完整出現”,所以AC自動機就可以(比廣義SAM好寫好調)

走一走屬於第j個串的路徑,對應的fail樹的祖先包含i(i<j)的結束位置,那麽可以轉移

所以,同理,走完i之後,整個fail樹子樹的dp值和val取max

但是註意一點,根節點標號是0(反正我trie都這樣寫)

代碼:

#include<bits/stdc++.h>
#define il inline
#define int long long
#define reg register int
#define mid ((l+r)>>1)
#define numb (ch^‘0‘)
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch==-)&&(fl=true
); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } namespace Miracle{ const int N=300000+5; int n,m; struct node{ int nxt,to; }e[2*N]; int hd[N],cnt; void add(int x,int y){ e[++cnt].nxt=hd[x]; e[cnt].to=y; hd[x]=cnt; } char s[N],b[N]; int len[N],st[N]; ll v[N],f[N];
int dfn[N],dfn2[N]; int df; struct seg{ ll mx; ll tag; }t[4*N]; void pushup(int x){ t[x].mx=max(t[x<<1].mx,t[x<<1|1].mx); } void pushdown(int x){ if(t[x].tag<=0) return; t[x<<1].tag=max(t[x<<1].tag,t[x].tag); t[x<<1].mx=max(t[x<<1].mx,t[x].tag); t[x<<1|1].tag=max(t[x<<1|1].tag,t[x].tag); t[x<<1|1].mx=max(t[x<<1|1].mx,t[x].tag); t[x].tag=0; } void upda(int x,int l,int r,int L,int R,ll c){ if(L<=l&&r<=R){ t[x].mx=max(t[x].mx,c); t[x].tag=max(t[x].tag,c); return ; } pushdown(x); if(L<=mid) upda(x<<1,l,mid,L,R,c); if(mid<R) upda(x<<1|1,mid+1,r,L,R,c); pushup(x); } ll query(int x,int l,int r,int p){ if(l==r){ return t[x].mx; } pushdown(x); if(p<=mid) return query(x<<1,l,mid,p); else return query(x<<1|1,mid+1,r,p); } void cle(int x,int l,int r){ t[x].mx=0;t[x].tag=0; if(l==r) return; cle(x<<1,l,mid);cle(x<<1|1,mid+1,r); } struct AC{ int fail[N],ch[N][26]; int cnt; void ins(char *s,int l){ //int len=strlen(s+1); int now=0; for(reg i=1;i<=l;++i){ int c=s[i]-a; if(!ch[now][c]) ch[now][c]=++cnt; now=ch[now][c]; } } void build(){ queue<int>q; for(reg i=0;i<26;++i){ if(ch[0][i]) fail[ch[0][i]]=0,q.push(ch[0][i]); } while(!q.empty()){ int x=q.front();q.pop(); for(reg i=0;i<26;++i){ if(ch[x][i]){ fail[ch[x][i]]=ch[fail[x]][i]; q.push(ch[x][i]); } else ch[x][i]=ch[fail[x]][i]; } } for(reg i=1;i<=cnt;++i){ add(fail[i],i); } } void clear(){ memset(fail,0,sizeof fail); cnt=0; memset(ch,0,sizeof ch); } void dfs(int x){ dfn[x]=++df; for(reg i=hd[x];i;i=e[i].nxt){ int y=e[i].to; dfs(y); } dfn2[x]=df; } ll wrk(char *s,int l,int id){ ll ret=0; int now=0; for(reg i=1;i<=l;++i){ int c=s[i]-a; now=ch[now][c]; // cout<<"now "<<now<<" i "<<i<<" dfn "<<dfn[now]<<endl; ret=max(ret,query(1,1,df,dfn[now])); } // cout<<dfn[now]<<".. "<<dfn2[now]<<endl; upda(1,1,df,dfn[now],dfn2[now],ret+v[id]); return ret; } }ac; void clear(){ ac.clear(); if(df)cle(1,1,df); df=0;cnt=0; n=0; memset(hd,0,sizeof hd); } int main(){ //return 0; int t; rd(t); while(t--){ clear(); rd(m); int tot=0; for(reg i=1;i<=m;++i){ scanf("%s",b+1); scanf("%lld",&v[i]); st[i]=tot+1; len[i]=strlen(b+1); for(reg j=tot+1;j<=tot+len[i];++j){ s[j]=b[j-tot]; } tot=tot+len[i]; ac.ins(b,len[i]); } // cout<<" after ac.ins "<<endl; ac.build(); ac.dfs(0);//find dfn ll ans=0; // cout<<" let‘s wrk "<<endl; for(reg i=1;i<=m;++i){ // cout<<" ii "<<i<<"--------------------"<<v[i]<<" len "<<len[i]<<" st "<<st[i]<<endl; //if(v[i]<=0) continue; for(reg j=st[i];j<=st[i]+len[i]-1;++j){ b[j-st[i]+1]=s[j]; } // cout<<b+1<<endl; f[i]=ac.wrk(b,len[i],i)+v[i]; // cout<<i<<" : "<<f[i]<<endl; ans=max(ans,f[i]); } printf("%lld\n",ans); } return 0; } } signed main(){ freopen("2963.in","r",stdin); freopen("2963.out","w",stdout); Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/2/3 11:36:24 */

fzyjojP2963 -- [校內訓練20161227]疫情控制問題