zoukankan      html  css  js  c++  java
  • luogu2282/bzoj1219 历史年份 (dp+hash+二分+线段树)

    luogu1415 拆分数列的加强版

    先考虑弱化版怎么做

    设f[i]表示某一串数,最后一个数的右端点是i时,它的左端点的最大值(也就是说,这一串数的最后一个数尽量小)

    那么有$f[j]=max{i+1|num[i+1,j]>num[f[i],i]}$

    这样推下去,f[N]就是最后一个数的最小值

    然后我们把它钦定住,再用类似的方式推回来,算出来最前面数的最大值

    直接做的话,转移$O(n)$,判断两数是否相等$O(n)$,所以总共是$O(n^3)$的

    显然过不了加强版,考虑如何优化。

    可以发现这个转移其实是固定左端点,找到一些右端点,使得这个数比当前的数大,那么只要找到第一个比它大的右端点,后面的就都比它大

    而且如果不考虑前缀0的话,恰好比它大的那个子串,长度就要么和它相等、要么是它的+1

    所以只需要找出来那个长度和它相等的子串,比较他俩的大小,要是比它小就加个1,然后把后面的都更新掉

    直接判定是$O(n)$的,但用hash先$O(n)$预处理,就可以做到$O(logn)$,具体做法是二分找出两个子串的LCP,再判断LCP+1的大小

    然后更新的时候用一个线段树维护区间取max、单点查询,也可以做到$O(logn)$

    所以复杂度$O(Tnlogn)$

    然而还有前缀0的问题。这样的话,我们就不能直接找和他长度相等的子串,而是要找去掉前缀0以后和它去掉前缀0以后长度相等的子串

    可以记一个nn0[i]表示i位置后面的第一个不是0的位置,pn0[i]表示i位置前面的第一个不是0的位置然后乱搞

    倒着做回来的时候都类似,然后我定义的g[i]是表示以i为左端点的最大右端点,也需要很注意前缀0的问题

    (有可能我发现长度相等的那个比它小,然后想往前顶一个,这时候应该顶到前面的第一个不为0的位置,否则加一个前缀0还是比它小)

    注意g的初值应该是g[pn0[f[N]]+1~f[N]]=N,因为你找到的那个最小值 加上一些前缀0还是最小值,这些都是合法的

    需要(?)特判全都是0的情况

    代码改来改去的写的很丑

    (不知道为什么,洛谷上开O2第一个点会OLE)

      1 #include<bits/stdc++.h>
      2 #define pa pair<int,int>
      3 #define CLR(a,x) memset(a,x,sizeof(a))
      4 using namespace std;
      5 typedef long long ll;
      6 typedef unsigned long long ull;
      7 const int maxn=2020,P=131;
      8 
      9 inline ll rd(){
     10     ll x=0;char c=getchar();int neg=1;
     11     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
     12     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
     13     return x*neg;
     14 }
     15 
     16 char num[maxn];
     17 int N,M,f[maxn],nn0[maxn],pn0[maxn];
     18 int laz[maxn<<2],ma[maxn<<2];
     19 ull hsh[maxn],bin[maxn];
     20 
     21 inline bool bigger(int x1,int x2,int l){
     22     int a=1,b=l,k=0;
     23     while(a<=b){
     24         int m=a+b>>1;
     25         if(hsh[x1+m-1]-hsh[x1-1]*bin[m]==hsh[x2+m-1]-hsh[x2-1]*bin[m]) a=m+1,k=m;
     26         else b=m-1;
     27     }
     28     if(k>=l) return 0;
     29     else return num[x1+k]>num[x2+k];
     30     return 0;
     31 }
     32 
     33 inline void pushdown(int p){
     34     if(!laz[p]) return;
     35     int a=p<<1,b=p<<1|1;
     36     ma[a]=max(laz[p],ma[a]),ma[b]=max(laz[p],ma[b]);
     37     laz[a]=max(laz[a],laz[p]),laz[b]=max(laz[b],laz[p]);
     38     laz[p]=0;
     39 }
     40 
     41 inline void change(int p,int l,int r,int x,int y,int z){
     42     ma[p]=max(ma[p],z);
     43     if(x<=l&&r<=y){
     44         laz[p]=max(laz[p],z);
     45     }else{
     46         pushdown(p);
     47         int m=l+r>>1;
     48         if(x<=m) change(p<<1,l,m,x,y,z);
     49         if(y>=m+1) change(p<<1|1,m+1,r,x,y,z);
     50     }
     51 }
     52 
     53 inline int query(int p,int l,int r,int x){
     54     if(l==r) return ma[p];
     55     int m=l+r>>1;
     56     pushdown(p);
     57     if(x<=m) return query(p<<1,l,m,x);
     58     else return query(p<<1|1,m+1,r,x);
     59 }
     60 
     61 int main(){
     62     //freopen(".in","r",stdin);
     63     int i,j,k;
     64     bin[0]=1;for(i=1;i<=2000;i++) bin[i]=bin[i-1]*P;
     65     while(~scanf("%s",num+1)){
     66         N=strlen(num+1);
     67         for(i=1;i<=N;i++)
     68             hsh[i]=hsh[i-1]*P+num[i];
     69         CLR(ma,0);CLR(laz,0);
     70         nn0[N+1]=N+1;
     71         for(i=N;i>=0;i--)
     72             nn0[i]=(num[i+1]!='0')?i+1:nn0[i+1];
     73         for(i=1;i<=N;i++)
     74             pn0[i]=(num[i-1]!='0')?i-1:pn0[i-1];
     75         change(1,1,N,1,N,1);
     76         for(i=1;i<=N;i++){
     77             f[i]=query(1,1,N,i);
     78             int y=nn0[i],nxt=y+i-nn0[f[i]-1]+1;
     79             if(bigger(y,nn0[f[i]-1],i-nn0[f[i]-1]+1)) nxt--;
     80             if(nxt<=N) change(1,1,N,nxt,N,i+1);
     81         }
     82         M=f[N];
     83         CLR(f,0);CLR(ma,0);CLR(laz,0);
     84         change(1,1,N,pn0[M]+1,M,N);
     85         for(i=M;i;i--){
     86             f[i]=query(1,1,N,i);
     87             int y=nn0[i-(f[i]-nn0[i-1]+1)-1],nxt;
     88             if(i-y<f[i]-nn0[i-1]+1||(i-y==f[i]-nn0[i-1]+1&&bigger(nn0[i-1],y,f[i]-nn0[i-1]+1))) nxt=pn0[y]+1;
     89             else nxt=y+1;
     90             if(nxt<=i-1) change(1,1,N,nxt,i-1,i-1);
     91         }
     92         if(N<nn0[0]) printf("%s",num+1); 
     93         else{
     94             for(i=1;i<=N;i=f[i]+1){
     95                 for(j=i;j<=f[i];j++)
     96                     putchar(num[j]);
     97                 if(f[i]!=N) putchar(',');
     98             }    
     99         }printf("
    ");
    100     }
    101     return 0;
    102 }
  • 相关阅读:
    常见名词解释
    主板结构解析
    计算机网络原理的总结
    Nginx的介绍
    优雅的python
    python小技巧
    python列表小程序
    学会浏览器查东西
    列表推导式
    深度优先算法与广度优先算法
  • 原文地址:https://www.cnblogs.com/Ressed/p/9869161.html
Copyright © 2011-2022 走看看