纪中集训2019.08.21JZOJ6315数字
Posted hansue
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了纪中集训2019.08.21JZOJ6315数字相关的知识,希望对你有一定的参考价值。
题意:
设$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;
小结:
应对神奇大模拟,优秀的模型往往会有事半功倍的效果。
以上是关于纪中集训2019.08.21JZOJ6315数字的主要内容,如果未能解决你的问题,请参考以下文章