zoukankan      html  css  js  c++  java
  • 【纪中集训2019.08.21】【JZOJ6315】数字

    题目链接

    题意:

      设$s(i)$为将$1sim i$看做字符串后依次连接形成的串。给定正整数$n$,求最小的$i$使得$n$是$s(i)$的字串。$T$组数据。

      $nle 10^{17}, ; tle 10^4$

    分析:

      不能模拟$s(i)$的组成过程来找答案,时间不能承受。

      也不能预处理$s(k)$,空间不能承受。

      那就只能在$n$上找答案。

      以下把数字当成字面量来讨论,更方便。

      同时,这里讨论的前缀和后缀不包括本身。

      思考一下,答案分为三种:

      1.$ans=n$

      2.$n$由$ans$的前缀和$ans-1$的后缀组成

      3.$n$由$ans-k$的后缀和$ans-k+1 , \, ans-k+2 dots ans-2 , \, ans-1$整串和$ans$的前缀组成

      那么把三类答案的所有可能取最小值即可。

      

      先确定一下我们模拟的工具。用字符串还是数字?

      字符串更方便控制位置,数字在比较、增减的时候更方便。

      我这里用一种取两家之长的做法:

      1.以五倍最大长度($N=17$)存储每一位数字

      2.用头尾指针记录数字的位置,初始化数字首位在$2*N+1$上。非数字位数值为$-1$,比较时视作通配符。

      3.定义左移、右移、找零、判九等函数辅助操作

      个人感觉这个模型的灵活度很高,适用于数字$ imes$字符串的操作。

      现在看到第二类答案。

      首先枚举“切一刀”的位置,设分离出的数字为$x$和$y$,将$y$从最左边开始向右卡位,尝试匹配。

      边界一:$y$的右侧不能和$x$的右侧平齐。连续的自然数数值是有变化的,如果两个数字的右侧平齐,甚至$y$的右侧越过$x$的右侧,$x$必然不是$ans-1$的后缀。

      边界二:$y$的左侧不能和$x$的左侧平齐。这和我们的定义相违背:$ans$相邻的数字不是$n$的子串。

      注意,这里的“匹配”,有可能有进位。

      看到第三类答案。

      首先枚举基准数,再将它的相邻数字往左、右匹配。这里凸显出了数据模型的灵活性。

      基准数不能等于原数。

      数字减少时可能会出现$0$,注意应对。

      注意数字位数的变化,左右移动的距离要根据当前数字的长度来。

    实现(100分):

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define IL inline
    using namespace std;
    typedef long long LL;
    const int N=17;
    
    IL void swap(LL &x,LL &y){
        LL t=x;    x=y;    y=t;
        
    }
    
        int T;
        LL n;
    
    struct Num{
        LL s[N*5+1];
        int p,q;
        
        IL LL operator[](int i){
            return s[i];
            
        }
        
        IL int len(){
            return q-p+1;
            
        }
        
        IL bool err(){
            if(p>q)
                return true;
            if(s[p]==0)
                return true;
            for(int i=p;i<=q;i++)
            if(s[i]==-1)
                return true;
            return false;
            
        }
        
    }org;
    
    IL Num fill(LL x){
        Num a;
        memset(a.s,-1,sizeof a.s);
        int l=0;
        while(x>0){
            a.s[++l]=x%10LL;
            x/=10LL;
            
        }
        for(int i=1;i<=l/2;i++)
            swap(a.s[i],a.s[l-i+1]);
        
        for(int i=l;i>=1;i--)
            a.s[2*N+i]=a.s[i];
        for(int i=1;i<=2*N;i++)
            a.s[i]=-1;
        a.p=2*N+1;    a.q=2*N+l;
        
        return a;
        
    }
    
    IL LL val(Num a){
        LL ret=0;
        for(int i=a.p;i<=a.q;i++)
            ret=ret*10LL+a[i];
        return ret;
        
    }
    
    IL Num copy(Num a,int l,int r){
        for(int i=a.p;i<=a.q;i++)
        if(i<l||i>r)
            a.s[i]=-1;
        a.p=l;    a.q=r;
        return a;
        
    }
    
    IL Num shl(Num a,int k){
        int p1=a.p-k,q1=a.q-k;
        for(int i=a.p;i<=a.q;i++)
            a.s[i-k]=a[i];
        for(int i=q1+1;i<=a.q;i++)
            a.s[i]=-1;
        a.p=p1;    a.q=q1;
        return a;
        
    }
    
    IL Num shr(Num a,int k){
        int p1=a.p+k,q1=a.q+k;
        for(int i=a.q;i>=a.p;i--)
            a.s[i+k]=a[i];
        for(int i=a.p;i<p1;i++)
            a.s[i]=-1;
        a.p=p1;    a.q=q1;
        return a;
        
    }
    
    IL bool eql(Num a,Num b,int l,int r){
        for(int i=l;i<=r;i++)
        if(a[i]==-1||b[i]==-1)
            continue;
        else 
        if(a[i]!=b[i])
            return false;
        return true;
        
    }
    
    IL bool operator<(Num a,Num b){
        return val(a)<val(b);
        
    }
    
    IL int f0(Num a){
        int ret=a.q;
        while(a[ret]==0)
            ret--;
        return ret+1;
        
    }
    
    IL bool all9(Num a,int l,int r){
        for(int i=l;i<=r;i++)
        if(a[i]!=9)
            return false;
        return true;
        
    }
    
    IL Num operator+(Num a,Num b){
        for(int i=b.p;i<=b.q;i++)
            a.s[i]=b[i];
        a.q=b.q;
        return a;
        
    }
    
    IL Num inc(Num a){
        int pos=a.q;
        a.s[pos]++;
        while(a[pos]==10){
            a.s[pos]=0;
            a.s[--pos]++;
            
        }
        if(pos<a.p)
            a.s[--a.p]=1;
        return a;
        
    }
    
    IL Num dec(Num a){
        int pos=f0(a);
        a.s[pos-1]--;
        bool flag=false;
        if(a.p==pos-1&&a.s[pos-1]==0){
            flag=true;
            a.p++;
        }
        for(int i=pos;i<=a.q;i++)
            a.s[i]=9;
        if(flag)
            a=shl(a,1);
        return a;
        
    }
    
    int main(){
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
    
        scanf("%d",&T);
        while(T--){
            scanf("%lld",&n);
            
            Num org,ans;
            org=ans=fill(n);
            int l=org.len();
            
            for(int pos=org.q;pos>org.p;pos--){
                if(org[pos]==0)
                    continue;
                
                Num x=copy(org,org.p,pos-1);
                Num y=copy(org,pos,org.q);
                
                y=shl(y,l);
                while(y.q<x.q&&y.p<x.p){
                    int pos0=f0(y);
                    
                    if(eql(x,y,y.p,pos0-2)
                        &&all9(x,pos0,x.q)
                        &&(x[pos0-1]==-1
                         ||x[pos0-1]+1==y[pos0-1])){
                        Num z=copy(y,y.p,y.q);
                        for(int i=y.q+1;i<=x.q;i++)
                            z.s[i]=0;
                        z.q=x.q;
                        if(eql(y,z,y.p,y.q))
                            ans=min(ans,z);
                        
                    }
                    
                    if(eql(x,y,y.p,y.q)){
                        Num z=inc(y+copy(x,y.q+1,x.q));
                        if(eql(y,z,y.p,y.q))
                            ans=min(ans,z);
                        
                    }
                    
                    y=shr(y,1);
                    
                }
                
            }
            
            for(int i=org.p;i<=org.q;i++)
                for(int j=i;j<=org.q;j++){
                    if(j-i+1>=l)
                        continue;
                    if(org[i]==0)
                        continue;
                    
                    Num x=copy(org,i,j);
                    bool flag=true;
                    while(flag){
                        x=dec(x);
                        x=shl(x,x.len());
                        if(x.q<org.p)
                            break;
                        
                        if(x.err()||!eql(x,org,x.p,x.q))
                            flag=false;
                        
                    }
                    x=copy(org,i,j);
                    while(flag){
                        x=inc(x);
                        x=shr(x,x.len());
                        if(x.p>org.q)
                            break;
                        
                        if(!eql(x,org,x.p,x.q))
                            flag=false;
                        
                    }
                    
                    if(x.p>org.q)
                        x=dec(x);
                    
                    if(flag)
                        ans=min(ans,x);
                        
                }
            
            
            printf("%lld
    ",val(ans));
            
        }
    
        return 0;
    
    }
    View Code

    小结:

      应对神奇大模拟,优秀的模型往往会有事半功倍的效果。

  • 相关阅读:
    memcached全面剖析--3.memcached的删除机制和发展方向
    memcached完全剖析--1. memcached的基础
    memcached全面剖析--2.理解memcached的内存存储
    memcached内存管理机制[未整理]
    memcached缓存基本概念
    有关memcached企业面试案例讲解
    网关协议学习:CGI、FastCGI、WSGI
    Redis和Memcached的区别
    Linux 日志切割工具cronolog详解
    vim粘贴代码格式变乱
  • 原文地址:https://www.cnblogs.com/Hansue/p/11405092.html
Copyright © 2011-2022 走看看