zoukankan      html  css  js  c++  java
  • bzoj 3790 神奇项链(Manacher,DP+BIT | 贪心)

    【题意】

        你可以产生一个回文串,也可以将两个串合并成一个串,问产生目标串需要的最少合并次数。

    【思路】

      显然我们要先产生目标串中包含的极大回文字符串。

        Manacher求出每个位置可以向两边延伸的最长回文串。

        则题目转化为有若干条线段,求最少的线段将[1..n]覆盖。贪心DP皆可上,DP需要BIT优化一下。

    【代码】

     1 #include<set>
     2 #include<cmath>
     3 #include<queue>
     4 #include<vector>
     5 #include<cstdio>
     6 #include<cstring>
     7 #include<iostream>
     8 #include<algorithm>
     9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
    10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
    11 using namespace std;
    12 
    13 typedef long long ll;
    14 const int N = 2e5+10;
    15 const int inf = 1e9;
    16 
    17 struct Node
    18 {
    19     int l,r;
    20     bool operator < (const Node& rhs) const
    21     {
    22         return r<rhs.r;
    23     }
    24 } q[N];
    25 int tot;
    26 
    27 char s[N],a[N];
    28 int n,m,p[N];
    29 
    30 int C[N];
    31 void upd(int x,int v)
    32 {
    33     for(int i=x;i;i-=i&(-i)) 
    34         C[i]=min(C[i],v);
    35 }
    36 int query(int x)
    37 {
    38     if(x==0) return 0;
    39     int res=inf;
    40     for(int i=x;i<=n;i+=i&(-i))
    41         res=min(res,C[i]);
    42     return res;
    43 }
    44 
    45 void Add(int l,int r)
    46 {
    47     l=l/2+1,r=r/2-1;
    48     if(l>r) return ;
    49     q[++tot]=(Node){l,r};
    50 }
    51 void Manacher()
    52 {
    53     m=2*n+1;
    54     for(int i=1;i<=n;i++) 
    55     {
    56         a[i<<1]=s[i];
    57         a[i<<1|1]='#';
    58     }
    59     a[0]='+',a[m+1]='-',a[1]='#';
    60     int mx=0,id;
    61     for(int i=1;i<=m;i++)
    62     {
    63         if(mx>i) p[i]=min(mx-i,p[id*2-i]);
    64         else p[i]=1;
    65         while(a[i-p[i]]==a[i+p[i]]) p[i]++;
    66         Add(i-p[i],i+p[i]);
    67         if(p[i]+i>mx) mx=i+p[i],id=i;
    68     }
    69 }
    70 
    71 int dp()
    72 {
    73     int ans=inf;
    74     sort(q+1,q+tot+1);
    75     FOR(i,1,tot)
    76     {
    77         int x=query(q[i].l-1)+1;
    78         upd(q[i].r,x);
    79         if(q[i].r==n) ans=min(ans,x);
    80     }
    81     return ans;
    82 }
    83 
    84 int main()
    85 {
    86     while(scanf("%s",s+1)==1) 
    87     {
    88         memset(p,0,sizeof(p));
    89         tot=0;
    90         n=strlen(s+1);
    91         FOR(i,1,n) C[i]=inf;
    92         Manacher();
    93         printf("%d
    ",dp()-1);
    94     }
    95     return 0;
    96 }
  • 相关阅读:
    [CF1028D] Order book
    初入python,与同学者的第一次见面(小激动)
    jira与mysql的配合搭建调整
    linux内置的审计跟踪工具------last和lastb
    rman
    nginx和apache的一些比较
    NYOJ128前缀式计算
    NYOJ2括号配对问题
    大数加减乘以及高精度幂
    在不同的页面之间通过查询字符串传递信息
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5349157.html
Copyright © 2011-2022 走看看