zoukankan      html  css  js  c++  java
  • Codeforces 1163D Mysterious Code(AC自动机+DP)

    AC自动机 来做有点想不到,捞一手就是学一手。

    dp[ i ][ j ] 表示字符串 c 中的第 i 位到字典树上节点 j 的最大值是多少, word[ j ] 表示在节点 j 下对答案修改的值是多少。

    首先可以确定是 s t 塞入字典树时,他们的结尾节点的 word 值显然一个是 1 一个是 -1 ,接下来就是 fail 数组上的一波操作,对于当前节点 j ,我们的 word[ j ] 需要加上 word[ fail[ j ] ] ,即当选到当前节点 j 时候,加上可能匹配到的一个完整的 s 或者一个完整的的影响。假设 s = "baaaa" , t = "aa" ,当 j 节点在 s 下的第一个 ‘a' 时, fail[ j ] t 的第一个 ‘a’ , word[ j ] 不进行修改,当 j 节点在 s 下的第二个 'a' 时, fail[ j ] t 的第二个 ‘a' , word[ j ] 更新值为 word[ j ]-1 ,表示在匹配过程中到 s "baa" 时,恰好也匹配到了一个 t ,我们需要减去一个完整的 t 带来答案的影响,同理,到 s 的第三个 ‘a’ 不修改, s 的第四个 'a' 修改为 word[ j ]-1 ,那么word就是这么个作用。

    接下来转移方程就比较好理解了,设 id 为在节点 j 下的 ‘a' ~ ‘z’ 的任意一个节点值,显然只有在 c[ i ] 为匹配符或者   c[ i ] 恰好等于节点 j 下对应的字符才能进行转移,那么转移方程就是 dp[ i+1 ][ id ]=max(dp[ i+1 ][ id ],dp[ i ][ j ]+word[ id ]) ,最后只需要枚举在所有节点下的 i 等于 c.size() dp 值取 max 就是答案了。

      1 //      ——By DD_BOND 
      2 
      3 //#include<bits/stdc++.h>
      4 #include<functional>
      5 #include<algorithm>
      6 #include<iostream>
      7 #include<sstream>
      8 #include<iomanip>
      9 #include<climits>
     10 #include<cstring>
     11 #include<cstdlib>
     12 #include<cstddef>
     13 #include<cstdio>
     14 #include<memory>
     15 #include<vector>
     16 #include<cctype>
     17 #include<string>
     18 #include<cmath>
     19 #include<queue>
     20 #include<deque>
     21 #include<ctime>
     22 #include<stack>
     23 #include<map>
     24 #include<set>
     25 
     26 #define fi first
     27 #define se second
     28 #define MP make_pair
     29 #define pb push_back
     30 #define INF 0x3f3f3f3f
     31 #define pi 3.1415926535898
     32 #define lowbit(a)  (a&(-a))
     33 #define lson l,(l+r)/2,rt<<1
     34 #define rson (l+r)/2+1,r,rt<<1|1
     35 #define Min(a,b,c)  min(a,min(b,c))
     36 #define Max(a,b,c)  max(a,max(b,c))
     37 #define debug(x)  cerr<<#x<<"="<<x<<"
    ";
     38 
     39 using namespace std;
     40 
     41 typedef long long ll;
     42 typedef pair<int,int> P;
     43 typedef pair<ll,ll> Pll;
     44 typedef unsigned long long ull;
     45 
     46 const ll LLMAX=2e18;
     47 const int MOD=1e9+7;
     48 const double eps=1e-8;
     49 const int MAXN=1e6+10;
     50 
     51 inline ll sqr(ll x){ return x*x; }
     52 inline int sqr(int x){ return x*x; }
     53 inline double sqr(double x){ return x*x; }
     54 ll gcd(ll a,ll b){ return b==0? a: gcd(b,a%b); }
     55 ll exgcd(ll a,ll b,ll &x,ll &y){ ll d; (b==0? (x=1,y=0,d=a): (d=exgcd(b,a%b,y,x),y-=a/b*x)); return d; }
     56 ll qpow(ll a,ll n){ll sum=1;while(n){if(n&1)sum=sum*a%MOD;a=a*a%MOD;n>>=1;}return sum;}
     57 inline int dcmp(double x){  if(fabs(x)<eps) return 0;   return (x>0? 1: -1); }
     58 
     59 int tree[110][26],word[110],fail[110],cnt=0,dp[1010][110];
     60 
     61 void insert(string s,int v){
     62     int root=0;
     63     for(int i=0;i<(int)s.size();i++){
     64         int id=s[i]-'a';
     65         if(!tree[root][id]) tree[root][id]=++cnt;
     66         root=tree[root][id];
     67     }
     68     word[root]+=v;
     69 }
     70 
     71 void get_fail(){
     72     queue<int>q;
     73     for(int i=0;i<26;i++)
     74         if(tree[0][i]){
     75             fail[tree[0][i]]=0;
     76             q.push(tree[0][i]);
     77         }
     78     while(!q.empty()){
     79         int u=q.front();    q.pop();
     80         for(int i=0;i<26;i++)
     81             if(tree[u][i]){
     82                 fail[tree[u][i]]=tree[fail[u]][i];
     83                 q.push(tree[u][i]);
     84             }
     85             else    tree[u][i]=tree[fail[u]][i];
     86         word[u]+=word[fail[u]];
     87     }
     88 }
     89 
     90 int main(void)
     91 {
     92     ios::sync_with_stdio(false);    cin.tie(0);   cout.tie(0);   
     93     int ans=-INF;  string c,s,t;   cin>>c>>s>>t;
     94     insert(s,1);    insert(t,-1);     get_fail();
     95     memset(dp,-INF,sizeof(dp));
     96     dp[0][0]=0;
     97     for(int i=0;i<(int)c.size();i++)
     98         for(int j=0;j<=cnt;j++)
     99             for(int z=0;z<26;z++)
    100                 if(c[i]=='*'||'a'+z==c[i]){
    101                     int id=tree[j][z];
    102                     dp[i+1][id]=max(dp[i+1][id],dp[i][j]+word[id]);
    103                 }
    104     for(int i=0;i<=cnt;i++)   ans=max(ans,dp[c.size()][i]);
    105     cout<<ans<<endl;
    106     return 0;
    107 }
  • 相关阅读:
    WPF TreeView IsExpanded 绑定不上的问题
    WPF TreeView BringIntoViewBehavior
    WPF ListBox的进阶使用(二)
    WPF ListBox的进阶使用(一)
    双缓冲队列解决WPF界面卡死
    C# 对接Https接口
    软件架构的六大设计原则
    FeignClient接口封装
    CentOS修改root密码
    并发编程的挑战(Java并发编程的艺术)
  • 原文地址:https://www.cnblogs.com/dd-bond/p/10847508.html
Copyright © 2011-2022 走看看