2019 Multi-University Training Contest 8——Acesrc and Good Numbers(数学 想法)

109 篇文章 0 订阅
70 篇文章 1 订阅

original link - http://acm.hdu.edu.cn/showproblem.php?pid=6659

题意:

定义 F ( d , n ) F(d,n) F(d,n) 1 , 2... n 1,2...n 1,2...n的十进制下位中,数字d出现的个数,找出小于等于 n n n的最大的数 x x x使得 F ( d , x ) = x F(d,x)=x F(d,x)=x

解析:

神奇的做法,可惜比赛的时候在敲其他题目没有好好想过这题。

首先我们用数位 d p dp dp求出 F ( d , n ) = y F(d,n)=y F(d,n)=y,设 s u b = ∣ n − y ∣ sub=|n-y| sub=ny,由于减少每个数至多只会减少 18 18 18 d d d。所以我让 n n n往下缩小 ⌈ s u b 18 ⌉ \lceil\dfrac{sub}{18}\rceil 18sub

这样可以保证不会漏掉正解。

复杂度证明:

d = 1 d=1 d=1为例,假定 n = a 1 ∗ 1 0 18 + a 2 ∗ 1 0 17 + . . . n=a_1*10^{18}+a_2*10^{17}+... n=a11018+a21017+...,则有: F ( 1 , n ) = ( b 1 ≤ a 1 ) 1 0 18 + b 2 ∗ 1 0 17 + . . F(1,n)=(b_1\leq a_1)10^{18}+{b_2}*10^{17}+.. F(1,n)=(b1a1)1018+b21017+..

n = O ( k 1 x ) , F ( d , n ) = O ( k 2 x ) , ∣ n − F ( d , n ) ∣ = O ( k 3 x ) n=O(k_1x),F(d,n)=O(k_2x),|n-F(d,n)|=O(k_3x) n=O(k1x),F(d,n)=O(k2x),nF(d,n)=O(k3x),每次减小步长是 O ( x ) O(x) O(x)级的。所以循环次数不会很大。

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
LL ans;
int lim[20],up;
LL P10[20];
LL num[20];
LL ct(int len){
    if(len<=0)return 0;
    return 1ll*len*P10[len-1];
}
void dfs(int d,int pos){
    if(pos==0)return;
    for(int i=0;i<lim[pos];i++){
        if(i==d)ans+=P10[pos-1];
        ans+=ct(pos-1);
    }
    if(lim[pos]==d){
        ans+=num[pos-1]+1;
    }
    dfs(d,pos-1);
}
void deal(int d,LL R){
    ans=0;
    up=0;
    P10[0]=1;
    while(R){
        lim[++up]=R%10ll;
        P10[up]=P10[up-1]*10ll;
        R/=10ll;
    }
    for(int i=1;i<=up;i++){
        num[i]=num[i-1]+lim[i]*P10[i-1];
    }
    dfs(d,up);
}

int main(){
    int t;scanf("%d",&t);
    while(t--){
        int d;LL R;
        scanf("%d%lld",&d,&R);
        deal(d,R);
        while(ans!=R){
            R-=(abs(R-ans)+17ll)/18;
            deal(d,R);
        }
        printf("%lld\n",R);
    }
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值