【题解】数 [Bzoj5282]

【题解】数 [Bzoj5282]

传送门:数 \(\text{[Bzoj5282]}\)

【题目描述】

众所周知,萌萌哒六花不擅长数学,所以勇太给了她一些数学问题做练习,其中有一道是这样的:

一个正整数被称为是好的当且仅当它的十进制表示是其二进制表示的后缀。

例如正整数 \((100)_{10}\) 就是一个好的正整数,它的二进制表示是 \((1100100)_{2}\),而正整数 \((2)_{10}\)

就不是一个好的正整数,它的二进制表示是 \((10)_{2}\)。

现在勇太想要知道第 \(K\) 小的好的正整数。

当然,这个问题对于萌萌哒六花来说实在是太难了,你可以帮帮她吗?

【分析】

又是一道 \(\text{jiry_2}\) 搞出来报复社会的毒瘤题。。。

萌萌哒六花好评。

考试时瞎 \(jb\) 枚举搞到了 \(30pts\),然后就不会了。

考虑在一个 \(k\) 位十进制数 \((x)_{10}\) 的最前面加一个 \(1\) (即第 \(k+1\) 位)所产生的变化,对于数值大小来说增加了 \(10^k\),而这东西一定是 \(2^k\) 的倍数,所以在不考虑进位的情况下 \((x)_{2}\) 的第 \(k+1\) 位数值会增加 \(5^k\),考虑进位后可以发现对 \((x)_{2}\) 的后 \(k\) 位始终没有影响,于是暴力做法就出来了:

从小到大枚举 \(k\),用一个集合 \(Q\) 维护当前所有的合法数字,每次 \(k\) 增大后尝试在这些数的前面加 \(1/0\)(加 \(0\) 就是不变),并将合法的加入新集合,不合法的舍去。当求出第 \(K\) 个合法数字时就直接输出。

发现这玩意儿要写高精,但复杂度双双爆炸,按照吉司机的神仙思路,把大数压成 \((bit=2^{base})\) 进制(标程里面 \(base=25\)),复杂度直接降到 \(O(\frac{KL}{base})\)(\(L\) 为数字长度)。

(说实话这个复杂度的分析我是真没看懂,总之能过就行了...)

【Code】

#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#define LL long long
#define Re register int
using namespace std;
const int N=5e5+3;
const int bit=(1<<25),base=25;//bit:高精度大数的进制
struct Int{
    int l,a[150];
    Int(Re O=0){memset(a,0,sizeof(a)),a[l=1]=O;}
    inline void operator=(const int O){*this=Int(O);}
    inline void operator+=(const Int &O){//高精加高精
        l=max(l,O.l);
        for(Re i=1;i<=l;++i)a[i]+=O.a[i];l+=2;
        for(Re i=1;i<l;++i)if(a[i]>=bit)
            a[i+1]+=(a[i]>>base),a[i]&=(bit-1);//a[i+1]+=a[i]/bit,a[i]%=bit;
        while(l>1&&!a[l])--l;//去掉前导0
    }
    inline void operator*=(const int O){//高精乘低精
        for(Re i=1;i<=l;++i)a[i]*=O;l+=2;
        for(Re i=1;i<l;++i)if(a[i]>=bit)
            a[i+1]+=(a[i]>>base),a[i]&=(bit-1);//a[i+1]+=a[i]/bit,a[i]%=bit;
        while(l>1&&!a[l])--l;//去掉前导0
    }
    inline void print(){//转为十进制数输出
        vector<int>ans;
        while(l&&a[l]){
            Re yu=0;
            for(Re i=l,x;i>=1;--i)//高精除低精,即a/=10
                x=a[i],a[i]=((yu<<base)+x)/10,yu=((yu<<base)+x)%10;//即a[i]=(yu*bit+x)/10,yu=(yu*bit+x)%10
            ans.push_back(yu);//算出来的余数(a%10)就是十进制下的当前位的值
            while(l>1&&!a[l])--l;//去掉前导0
        }
        for(Re i=ans.size()-1;i>=0;--i)printf("%d",ans[i]);//获取值是从低位到高位,所以要倒叙输出
    }
    inline int judge(Re j){return a[j/base+1]&(1<<j%base);}//判断二进制下第j位的数值是否为1
}B,Q[N];
int K,O,fa[N];
inline int find(Re x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
//  freopen("number.in","r",stdin);
//  freopen("number.out","w",stdout);
    scanf("%d",&K),Q[fa[1]=O=1]=0,B=1;//先初始化一个0
    for(Re k=0;;++k){
        Re ed=find(O),pre=0;
        for(Re i=find(1);pre!=ed;pre=i,i=find(i+1)){
            Int tmp=Q[i];tmp+=B;//B: 10^k
            if(tmp.judge(k)){//十进制下第k位加1的情况,如果加上1*10^k之后二进制第k位为1则可以加入该点
                Q[++O]=tmp,fa[O]=O;
                if(!--K){tmp.print();return 0;}
            }
            if(Q[i].judge(k))fa[i]=find(i+1);//十进制下第k位加0的情况,如果二进制第k位为1则需要删掉该点
        }
        B*=10;
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/Xing-Ling/p/12699839.html

时间: 2024-10-15 12:45:23

【题解】数 [Bzoj5282]的相关文章

HDU 6108 小C的倍数问题 数论

小C的倍数问题 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6108 Description 根据小学数学的知识,我们知道一个正整数x是3的倍数的条件是x每一位加起来的和是3的倍数.反之,如果一个数每一位加起来是3的倍数,则这个数肯定是3的倍数.现在给定进制P,求有多少个B满足P进制下,一个正整数是B的倍数的充分必要条件是每一位加起来的和是B的倍数. Input 第一行一个正整数T表示数据组数(1<=T<=20).接下来T行,每行一个正整数P(

PAT 甲级 A1075 (2019/02/18)

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 10010; struct PAT_Student{ int id; //考号 int score[6]; //每道题的分数 bool flag; //是否有能通过编译的提交 int all_score; //总分 int prefect_problem;//完美题解数 }stu[MAX

【BZOJ1026】windy数题解

题面 [题目描述] windy定义了一种windy数.不含前导零且相邻两个数字之差至少为2的正整数被称为windy数. windy想知道,在A和B之间,包括A和B,总共有多少个windy数? [输入] 包含两个整数,A B. [输出] 一个整数. [输入样例一] 1 10 [输入样例二] 25 50 [输出样例一] 9 [输出样例二] 20 [数据规模和约定] 100%的数据,满足 1 <= A <= B <= 2000000000 . 题解 分析 头一次接触数位DP啊 然而这题只要这样

洛谷 P1106 删数问题 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1106 题目描述 键盘输入一个高精度的正整数N,去掉其中任意k个数字后剩下的数字按原左右次序将组成一个新的正整数.编程对给定的N和k,寻找一种方案使得剩下的数字组成的新数最小. 输出应包括所去掉的数字的位置和组成的新的正整数.(N不超过250位) 输入数据均不需判错. 输入输出格式 输入格式: n (高精度的正整数) k (需要删除的数字

CodeVS1039 数的划分 插图题解!

题目 题目描述 将整数n分成k份,且每份不能为空,任意两种划分方案不能相同(不考虑顺序). 例如:n=7,k=3,下面三种划分方案被认为是相同的. 1 1 5 1 5 1 5 1 1 问有多少种不同的分法. 输入描述 输入:n,k (6 输出描述 输出:一个整数,即不同的分法. 样例输入 7 3 样例输出 4 题解! 我们用dp[i][j]表示把数字i分成j份的方案数,那么: 1. i < j 时,不存在方案,dp[i][j]=0; 2. i >= j 时,考虑:     1) 当前方案存在“

Noip2006 2^k进制数题解

题目描述 Description 设r是个2k进制数,并满足以下条件: (1)r至少是个2位的2k进制数. (2)作为2k进制数,除最后一位外,r的每一位严格小于它右边相邻的那一位. (3)将r转换为2进制数q后,则q的总位数不超过w. 在这里,正整数k(1≤k≤9)和w(k<W≤30000)是事先给定的. 问:满足上述条件的不同的r共有多少个? 我们再从另一角度作些解释:设S是长度为w的01字符串(即字符串S由w个"0"或"1"组成),S对应于上述条件(3)

洛谷 P1005 矩阵取数游戏 题解

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=1005 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元

Noip2007矩阵取数游戏题解

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n?m的矩阵,矩阵中的每个元素ai,j均 为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值?2i, 其中i表示第i 次取数(从1 开始编号): 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

【基础练习】【字符串处理】codevs1264 芳香数题解

题目来源 2012CCC加拿大高中信息学奥赛(这个系列基本都是基础练习题,想打好最基础的基础的同学们可以试一试) 题目描述 Description This question involves calculating the value of aromatic numbers which are a combination of Arabic digits and Roman numerals. 本题是关于计算芳香数数值的问题,芳香数是阿拉伯数字和罗马数字的组合. An aromatic num