题意:一个数列是由 1 1 2 1 2 3 1 2 3 4 1 2 3 4 5 1 2 3 4 5 6.。。。。组成,也就是1-1,1-2,1-3......并且如果遇到多位数也要拆成数字比如1-10就是1 2 3 4 5 6 7 8 9 1 0共11个数字,问第K位是几?

分析:这可能是分享题里比较考验代码能力的题了,

这题唯一运用的算法可能就是二分吧

大体过程也非常好想

就是先确定离他最近且小于他的1-n是几,再算出来他是1-n+1中的答案

比如我要找11 那么离他最近且小于他的 1-n这个n就是4 因为1 1 2 1 2 3 1 2 3 4,此时数列已经10个数了,如果再补个1-5就超过11了

然后显然只需要在1-5中找第11-10个数字是多少就行了,得到答案1

找最近的1-n是几首先你要能算出来对于给定的n,能求出1-n有多少位,再用二分枚举出这个n是几,

二分大家肯定都能想到,问题是怎么计算1-n有多少位

这里我定义sum 1-n是指形如1 1 2 1 2 3 1 2 3 4.。。。1 2。。。 n这种的数字数

num 1-n是指形如1 2 3 。。。。n这种的数字数

先想如何求出num来,

很容易想到,这就是个简单的估计都不算数位dp的数位dp

位数有i位的数显然共有i*(10^i-10^i-1)个数字,因为你长达i位的数显然有10^i-10^i-1个,比如2位的数有10,11,。。。。,99共100-10=90个数

每个数字都有i位,很容易得到这个结论

那么任意的n,num也就很好求了

只需要把比他位数小的求个和,(设n有i位)再加上(n-(10^i-1)+1)*i,这个也很容易推出来,和上面几乎一样

那么求num 的代码也就很好写

ll chuli_num(int x)
{
int i;
ll ans=0ll;
for(i=;i<=;i++)
{
if(pow_10[i]>x) break;
ans+=(ll)(pow_10[i]-pow_10[i-])*i;
}
ans+=(ll)(x-pow_10[i-]+)*i;
return ans;
}

然后就是求sum

考虑和求num的过程类似,只不过式子不太一样

在求i位的数的sum值时,可以想一下他长什么样,显然是1-10 1-11 1-12 1-13 ......1-99

直接遍历一遍然后调用求num的函数显然会t

不难发现的是1-11比1-10只多了一个11,也就是两位,所以其实这是一个等差数列求和

首项a1就是1-10^i-1的num值,公差d就是位数i,项数n还是10^i-10^i-1

sum=n*a1+n*(n-1)/2*d

当然任意n值也是一样用等差数列求和, 只不过项数变了而已

代码也能写出来了

ll chuli_sum(int x)
{
int i;
ll ans=0ll;
for(i=;i<=;i++)
{
if(pow_10[i]>x) break;
int n=pow_10[i]-pow_10[i-];
int a1=chuli_num(pow_10[i-]);
ans+=(ll)n*a1+(ll)n*(n-)/*i;
}
int n=x-pow_10[i-]+;
int a1=chuli_num(pow_10[i-]);
ans+=(ll)n*a1+(ll)n*(n-)/*i;
return ans;
}

插句嘴,这题k是1e18,显然最大的n数,怎么也不可能超过1e9,因为光每个数都只算1位都有n*(n+1)/2个数,这已经与1e18很接近了

而就是因为这个将近1e9的数,原本一个只需要递推求num与sum的方法数组开不下,时间也不允许,

for(int i=;i<=;i++) for(int j=pow_10[i-];j<pow_10[i];j++) a[j]=a[j-]+i,b[j]=b[j-]+a[j];

这里a就是num数组,b就是sum数组,这只有一行的递推代码显然要比上面的要好写数倍

接下来就是二分的过程了,

首先显然是从sum里找不超过k的最大的sum了

l等于0就行,r取1e9就行,这个二分显然最后结束是要的r的值,这玩意不用再讲了吧。。

l=,r=;
while(l<=r)
{
mid=l+r>>;
now=chuli_sum(mid);
if(now>k) r=mid-;
else if(now==k)
{
r=mid;
break;
}
else l=mid+;
}

然后k要减去r对于的sum值,再对num进行一次二分

这次的r’显然不会超过r,因为这次的数字本应就只能取1-r+1,而取r+1显然会被归到二分结果是r+1的那种情况里,所以显然最终结果不会超过r

这里我们依然是找小于等于k的最大的num值,

而k与这个值的差就是我们选的下一个数字的第几位

比如现在剩下k还剩2位,下一个数是123456

那么我们要的就是2

这里怎么处理都可以

我是先算出123456的位数,再抹掉3456,最后mod10,

这里用啥方法都行,

能取出2来就行

int i;
for(i=;i<=;i++) if(pow_10[i]>r+) break;
printf("%d\n",(r+)/pow_10[i-k]%);

最后的话,这几块代码中间还有一点点细节,也很容易看懂

比如,在第一次sum后剩余的k如果是0的话,就要输出r的num值的最后一位(显然)

再或者,在第二次sum后剩余的k如果是0的话,就要输出r的值的最后一位(显然++)

这些分开写可能都挺好写的,但合在一起任何一个环节出错就没分了,所以挺考验代码能力的

代码:

#include<cstdio>
#include<algorithm>
using namespace std; #define ll long long int pow_10[]={,,,,,,,,,}; ll chuli_num(int x)
{
int i;
ll ans=0ll;
for(i=;i<=;i++)
{
if(pow_10[i]>x) break;
ans+=(ll)(pow_10[i]-pow_10[i-])*i;
}
ans+=(ll)(x-pow_10[i-]+)*i;
return ans;
} ll chuli_sum(int x)
{
int i;
ll ans=0ll;
for(i=;i<=;i++)
{
if(pow_10[i]>x) break;
int n=pow_10[i]-pow_10[i-];
int a1=chuli_num(pow_10[i-]);
ans+=(ll)n*a1+(ll)n*(n-)/*i;
}
int n=x-pow_10[i-]+;
int a1=chuli_num(pow_10[i-]);
ans+=(ll)n*a1+(ll)n*(n-)/*i;
return ans;
} int main()
{
int q,l,r,mid;
ll k,now;
scanf("%d",&q);
while(q--)
{
scanf("%lld",&k);
l=,r=;
while(l<=r)
{
mid=l+r>>;
now=chuli_sum(mid);
if(now>k) r=mid-;
else if(now==k)
{
r=mid;
break;
}
else l=mid+;
}
k-=chuli_sum(r);
if(!k)
{
printf("%d\n",r%);
continue;
}
l=;
while(l<=r)
{
mid=l+r>>;
now=chuli_num(mid);
if(now>k) r=mid-;
else if(now==k)
{
r=mid;
break;
}
else l=mid+;
}
k-=chuli_num(r);
if(!k)
{
printf("%d\n",r%);
continue;
}
int i;
for(i=;i<=;i++) if(pow_10[i]>r+) break;
printf("%d\n",(r+)/pow_10[i-k]%);
}
return ;
}

题目分享C 二代目的更多相关文章

  1. 题目分享E 二代目

    题意:一棵点数为n的树,每个节点有点权,要求在树中中找到一个最小的x,使得存在一个点满足max(该点点权,该点相邻的点的点权+1,其他点的点权+2)=x 分析:首先要能把题目转化为上述题意 首先题目让 ...

  2. 题目分享D 二代目

    题意:给定一个T条边的无向图,求S到E恰好经过N条边的最短路径 T≤100 N≤1000000 分析:(据说好像假期学长讲过) 首先很容易想到的是dp[i][j][k]表示从i到j经过k条边的最短路径 ...

  3. 题目分享H 二代目

    题意:有m个限制,每个限制l1,r1,l2,r2四个数,限制了一个长度为n的数第l1到r1位要与第l2到r2相同,保证r1-l1=r2-l2,求在限制下一共有多少种数 分析: 暴力的话肯定是从l1-r ...

  4. 题目分享G 二代目

    题意:有n组数,每组包含两个数,问在每组只能取一个的前提下能组成的最长的从1开始的连续自然数有几个? 分析:刚学了差分约束系统,很容易往转换成图的方向去想 将他读入的这n组数当成边读入 很容易会得到一 ...

  5. 题目分享F 二代目

    题意:T个点R种双向边,P种单向边,求点S到每个点的最短距离 分析:(这再看不出来是spfa就该**了) 首先,这题能否用spfa就看他是否有负环呗,显然,双向边的权值非负,单向边还有个啥政策,总之显 ...

  6. 2019年腾讯PHP程序员面试题目分享

    有需要学习交流的友人请加入交流群的咱们一起,有问题一起交流,一起进步!前提是你是学技术的.感谢阅读! 点此加入该群​jq.qq.com 1. php 的垃圾回收机制 PHP 可以自动进行内存管理,清除 ...

  7. 20190924-LeetCode解数独题目分享

    解决数独 题目描述 编写一个程序,通过已填充的空格来解决数独问题. 一个数独的解法需遵循如下规则: 数字 1-9 在每一行只能出现一次. 数字 1-9 在每一列只能出现一次. 数字 1-9 在每一个以 ...

  8. 题目分享X

    题意:一张票有n位数,如果这张票的前一半数字的和等于后一半数字的和(n一定是偶数),就称这张票为快乐票.有些数被擦除了,标记为’?’(’?‘的个数也是偶数),现在Monocarp 和 Bicarp 进 ...

  9. 题目分享V

    题意:现在两个人做游戏,每个人刚开始都是数字1,谁赢了就能乘以k^2,输的乘以k(k可以是任意整数,每次不一定相同)现在给你最终这两个人的得分,让你判断是否有这个可能,有可能的话Yes,否则No. 分 ...

随机推荐

  1. 【硬核】使用替罪羊树实现KD-Tree的增删改查

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习的第16篇文章,我们来继续上周KD-Tree的话题. 如果有没有看过上篇文章或者是最新关注的小伙伴,可以点击一下下方的传送门: ...

  2. ThinkPHP5中raw的作用

    在tp5中,我们一般在模板中输出变量是这样的:{$test} 但是有时候在有些源码中我们可以看到这样的方式:{$test|raw} 这个时候如果你去找手册会发现,全文基本没有提到这个raw的作用. 那 ...

  3. mysql导出

    --all-databases , -A 导出全部数据库. mysqldump -uroot -p --all-databases --all-tablespaces , -Y 导出全部表空间. my ...

  4. 22.3 Extends 构造方法的执行顺序

    /** 1.有子父类继承关系的类中,创建父类对象未调用,执行父类无参构造* 2.有子父类继承关系的类中,创建子类对象未调用,执行顺序:默认先调用 父类无参构造---子类无参构造* 在子类的构造方法的第 ...

  5. java集合中的一个移除数据陷阱(遍历集合自身并同时删除被遍历数据)

    下面是网上的其他解释,更能从本质上解释原因:Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁. Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量 ...

  6. Win10安装Keras+Tensorflow+Opencv

    Win10安装keras 安装 Anaconda 清华加速下载链接: https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/ 我选择的版本是: A ...

  7. Linux终端命令格式

    01.终端命令格式 command [-options] [parameter] 说明: command:命令名,响应功能的英文单词或单词的缩写 [-options]:选项,可用来对命令进行控制,也可 ...

  8. 第二章:shell变量

    查看所有全局和局部变量:delare和set 查看所有全局变量:env 定义环境变量: 用户变量在家目录下的~/.bash_profile和~/.bashrc中设置 全局变量在/etc/profile ...

  9. 不同目录有同名proto文件情况下,protoc生成.cc/.h

    首先先参考一下别人的博客,看完了,看懂了,再回过头来看我下面说的情况. 链接 https://blog.csdn.net/CAir2/article/details/78201572 但是这个也就是基 ...

  10. tortoise 设置beyond Compare比较工具

    1.桌面右击tortoiseSVN->setting->Diff Viewer面板,选择external,选中beyond Compare路径