【纪中集训2019.08.21】【JZOJ6315】数字

题目链接

题意:

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

  $n\le 10^{17}, \; t\le 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.定义左移、右移、找零、判九等函数辅助操作

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

  现在看到第二类答案。

  首先枚举“切一刀”的位置,设分离出的数字为$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\n",val(ans));

    }

    return 0;

}

小结:

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

原文地址:https://www.cnblogs.com/Hansue/p/11405092.html

时间: 2024-08-30 14:52:41

【纪中集训2019.08.21】【JZOJ6315】数字的相关文章

【纪中集训2019.08.20】【JZOJ6310】Global warming

题目链接 题意: 给出一个长度为$n$的序列$\{a_n\}$. 已知一个正整数$x$,你有一次机会指定区间$[l,r]$,令$\forall i\in [l,r],\;a_i=a_i+d\,(|d|\le x)$. 求最大化的最长上升子序列的长度. $1 \le n \le 2 \times 10^5 , \quad 1 \le a_i,x \le 10^9$且均为正整数. 分析: 可以很容易发现三个性质: 性质一:抬升$[l,r]$不优于抬升$[l,n]$,降低$[l,r]$不优于降低$[1

纪中集训2019.11.08

A.三角形计数 题目链接 题意: 咕 分析: 咕 实现: 咕 小结: 咕 B.Isaac 题目链接 题意: 咕 分析: 咕 实现: 咕 小结: 咕 C.字符消除 题目链接 题意: 咕 分析: 咕 实现: 咕 小结: 咕 当天总结: 咕 原文地址:https://www.cnblogs.com/Hansue/p/11826709.html

【纪中集训2019.3.12】Mas的仙人掌

题意: ? 给出一棵\(n\)个点的树,需要加\(m\)条边,每条边脱落的概率为\(p_{i}\) ,求加入的边在最后形成图中仅在一个简单环上的边数的期望: 题解: 考虑每一条边的贡献是\((1-p_{i})*\Pi_{j}p_{j}(j!=i)\),这里\(j\)和\(i\)不能同时加入: 一条加入的边可以看成一条树上路径 ,即求所有和路径\(i\)相交的路径\(j\)的\(p_{j}\)的乘积: 将一条树上的链\((u,v)\)拆成两条\((u,lca)\)和\((v,lca)\); 这样会

【纪中集训2019.3.29】整除分块

题目 描述 ? 本题的背景是整除分块: ? 定义一个数列$a_{n,i} ? = ?\lfloor \frac{n}{i} \rfloor $ ; ? 求$\sum_{i=l}^{r} mex(a_n) $ ; ? 其中\(mex\)表示序列中最小的没有出现过的自然数: ? 答案对\(998244353\)取模 : 范围 ? \(1 \le T \le 65536 \ , \ 1 \le l ,r \le 10^{36}\) : ? 评测系统支持使用 $ _ _ int218 $ ,但是不能直接

【纪中集训2019.3.20】河

题目 描述 给出\(n\)条河流,每条河流是形式为\(k_{i}x+b_{i}\)的一次函数且只有\(x\)轴正半轴的部分: 河流的污染部分和另外一条河流的干净部分交汇,干净的部分会被污染: 有若干个工厂要建在\(b_{i}\)处,问有多少种方案使得所有的河流在无穷远处被污染: 答案对\(1e9+7\)取模 范围 $1 \le N \le 5 \times 10^5 ? ?, ??|k_{i}|,|b_{i}| \le 10^9 $ 保证\(b_{i}\)互不相同: 题解 需要先找到可以被一条河

【纪中模拟2019.08.03】【JZOJ1308】取数游戏

题目链接 题意: N个正整数围成一圈,规则如下: •两个玩家轮流取数:•先手玩家取任意一个数x:•从第二步开始当前玩家只能取x(上一玩家取的数)相邻的数:•直到取完所有的数,游戏结束:•取得较多奇数的玩家获胜. 保证双方都采取最优策略的同时,计算先手有多少种取法获胜. $1\le N\le 10^2,\quad 1\le x\le 10^3$ 实现(100分): 因为笔者不会SG函数,所以如果有绕弯子的描述请谅解. 分析博弈过程,有$2^n$种形势,按博弈写程序会T. 考虑DP,貌似取数的过程有

【纪中模拟2019.08.17】【JZOJ3503】粉刷

题目链接 题意: 给定一个$N\times M$的$01$矩阵,要求覆盖所有$1$的位置,求最小操作次数.一次操作,可以竖着覆盖连续的最多$C$列,或者横着覆盖连续的最多$R$行. $1\le\;N,\;M,\;R,\;C\le\;15$ 分析: 数据范围较小,考虑枚举. 但是不能盲目地同时枚举覆盖行.覆盖列的操作,因为这样的枚举是$O (2^{2N})$的,会$T$. 考虑枚举覆盖行的操作,枚得一种方案之后贪心地计算覆盖列的操作,完成. 总的时间复杂度$O (N^3\times 2^N)$.

纪中集训2019.11.06

A.困难的图论 题目链接 题意: 给出由$n$个点和$m$条边构成的无向连通图,要求选出一些边.一条边被选中当且仅当它恰好被一个简单环经过. 一个环被称为简单环,当且仅当这个环上的所有点都只在这个环中被经过了一次. 输出这些边的编号的异或和.边从$1$开始编号. $1\le n\le 10^6,\;1\le m\le min\{10^6,n\times (n+1) /2\}$. 分析: 注意:一个图可能有很多简单环,题目要求选中所有简单环上的边.考场上我就是这一点搞错了.(其实搞对了也很可能做不

纪中集训2019.11.07

A.极好的问题 题目链接 题意: 咕 分析: 咕 实现: 咕 小结: 咕 B.背包问题 题目链接 题意: 咕 分析: 咕 实现: 咕 小结: 咕 C.子树问题 题目链接 题意: 咕 分析: 咕 小结: 咕 当天总结: 咕 原文地址:https://www.cnblogs.com/Hansue/p/11811824.html