zoukankan      html  css  js  c++  java
  • [2019杭电多校第一场][hdu6583]Typewriter(后缀自动机&&dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6583

    大致题意是说可以花费p在字符串后添加一个任意字符,或者花费q在字符串后添加一个当前字符串的子串。问最少花费多少可以得到目标串。

    一开始想到的dp,dp[i]为得到目标串的1-i的最小花费。

    那么dp[i]=min{dp[i-1]+p,dp[j-1]+q},s[j~i]应该为s[1~j-1]的子串。

    我们可以知道dp数组是一个单调递增的数组,用反证法可以证明:dp[i]由dp[i-1]转移就不用说了,如果dp[i]是由dp[j]转移过来且dp[i-1]>dp[i],那么dp[i-1]也可以由dp[j]转移过来,所以不合法。

    因为dp数组是递增的,则dp[i]如果是由第二种方法转移过来,则j应该是最小的。所以求最小的j满足s[j~i]应该为s[1~j-1]的子串。

    dp[i]的第二种转移位置,应该在是dp[i-1]的第二种转移位置j的基础上往后移。

    所以用双指针的位置,一个代表i,一个代表j,每次在后缀自动机上添加第j个位置的字符,如果s[j~i]在后缀自动机上可以匹配,则转移,不然就把j往后移。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cstring>
     6 #include<string>
     7 #include<queue>
     8 using namespace std;
     9 typedef long long ll;
    10 const ll maxn = 2e5 + 10;
    11 const ll inf = 1e18;
    12 struct SAM {
    13     int cnt, last, now;
    14     int len[maxn * 2], ch[maxn * 2][30], fa[maxn * 2];
    15     void clear() {
    16         for (int i = 0; i <= cnt; i++) {
    17             len[i] = fa[i] = 0;
    18             memset(ch[i], 0, sizeof(ch[i]));
    19         }
    20     }
    21     void insert(int x) {
    22         int np = ++cnt, p = last;
    23         len[np] = len[p] + 1, last = np;
    24         while (p && !ch[p][x])
    25             ch[p][x] = np, p = fa[p];
    26         if (!p)
    27             fa[np] = 1;
    28         else {
    29             int q = ch[p][x];
    30             if (len[q] == len[p] + 1)
    31                 fa[np] = q;
    32             else {
    33                 int nq = ++cnt;
    34                 len[nq] = len[p] + 1;
    35                 memcpy(ch[nq], ch[q], sizeof(ch[nq]));
    36                 fa[nq] = fa[q];
    37                 fa[np] = fa[q] = nq;
    38                 while (p&&ch[p][x] == q)
    39                     ch[p][x] = nq, p = fa[p];
    40             }
    41         }
    42     }
    43     int Match(int x) {
    44         return ch[now][x];
    45     }
    46     void withdraw(int lens) {
    47         while (now&&len[fa[now]] >= lens)now = fa[now];
    48         if (now == 0)now = 1;
    49     }
    50     void Tran(int x, int lens) {
    51         now = ch[now][x];
    52         if (now == 0)now = 1;
    53         withdraw(lens);
    54     }
    55 }SA;
    56 ll dp[maxn];
    57 char s[maxn];
    58 int main() {
    59     while (~scanf("%s", s + 1)) {
    60         ll p, q, len;
    61         memset(dp, 0, sizeof(dp));
    62         scanf("%lld%lld", &p, &q);
    63         len = strlen(s + 1);
    64         SA.cnt = SA.last = SA.now = 1;
    65         SA.insert(s[1] - 'a');
    66         dp[1] = p;
    67         int l = 2, r = 1;
    68         for (int i = 2; i <= len; i++) {
    69             r++;
    70             dp[i] = dp[i - 1] + p;
    71             while ((!SA.Match(s[i] - 'a') || r - l + 1 > (i + 1) / 2) && l <= r) {
    72                 SA.insert(s[l++] - 'a');
    73                 SA.withdraw(r - l);
    74             }
    75             SA.Tran(s[i] - 'a', r - l + 1);
    76             if (l <= r)
    77                 dp[r] = min(dp[r], dp[l - 1] + q);
    78         }
    79         printf("%lld
    ", dp[len]);
    80         SA.clear();
    81     }
    82 
    83 }
    View Code
  • 相关阅读:
    Windows下配置nginx+php(wnmp)
    nginx缓存优先级(缓存问题者必看)
    OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能
    M3U8文件简介
    拼车旅游网站 导航
    将jsp页面内容保存到excel(转)
    queryRuner如何获得bean对象,当这个bean对象中包含其他对象的时候
    js的trim方法(转)
    二进制运算误差问题
    myeclipes如何调试web项目
  • 原文地址:https://www.cnblogs.com/sainsist/p/11307838.html
Copyright © 2011-2022 走看看