2020 ICPC 台北区域赛 K - Number with Bachelors

题意:

一个数如果没有任何两位的数字是相同的,则该数称为B数,有两种询问:

  • 问[a,b]区间有多少个B数(在10/16进制下)
  • 问第k个B数是什么(在10/16进制下)

思路:

显然第一类问题可以用数位DP求解,第二类问题就是在数位dp外面套个二分就可以求解。由于输入的数都是unsigned long long,有一些细节需要注意,比如边界特判等。二分的时候采用左开右闭,因为如果[0,a]存在k个B数,那么此时二分的右边界就是a,且可以取到。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
inline bool test(int x,int y){
    if((x>>y)&1)return 1;
    else return 0;
}
char domin;
int a[21],len;
ull dp[21][1<<16|1][2][2];
ull dfs(int pos,int limit,int lead,int st,int base){
    if(pos==0) return !lead;
    if(!limit && dp[pos][st][lead][base==10?0:1]!=-1)
        return dp[pos][st][lead][base==10?0:1];
    ull ans=0;
    int maxx=limit?a[pos]:base-1;
    for(int i=0;i<=maxx;i++){
        if(!test(st,i)){
            ans+=dfs(pos-1,limit&&i==maxx,lead&&i==0,(lead&&i==0)?0:st|(1<<i),base);
        }
    }
    if(!limit) dp[pos][st][lead][base==10?0:1]=ans;
    return ans;
}
ull solve1(ull x){
    len=0;
    int base=domin=='d'?10:16;
    while(x){
        a[++len]=x%base;
        x/=base;
    }
    return dfs(len,1,1,0,base);
}
void input(ull &a){
     if(domin=='d')
        scanf("%llu",&a);
     else{
        a=0;
        char ch=getchar();
        while(!(ch>='0' && ch<='9')&&!(ch>='a' && ch<='f')) ch=getchar();
        while( (ch>='0' && ch<='9')||(ch>='a' && ch<='f') ){
            a=a*16;
            if(ch>='a')
                a+=10+ch-'a';
            else
                a+=ch-'0';
            ch=getchar();
        }
     }
}
void print(ull a){
    if(a==0){
        puts("0");return;
    }
    if(domin=='d'){//10
        printf("%llu\n",a);return;
    }
    //16
    vector<int>ans;
    while(a){
        ans.push_back(a%16);
        a/=16;
    }
    for(int i=ans.size()-1;i>=0;i--){
        if(ans[i]>=10)
            printf("%c",'a'+ans[i]-10);
        else
            printf("%d",ans[i]);
    }
    puts("");
}
int main () {
    domin='h';
    memset(dp,-1,sizeof dp);
    int T;
    scanf("%d",&T);
    while(T--){
        ull a,b,i;
        scanf(" %c",&domin);
        int typ;scanf("%d",&typ);
        if(typ==0){
            input(a);
            input(b);
            ull ans=solve1(b);
            if(a==0)ans++;
            else{
                ans-=solve1(a-1);
            }
            print(ans);
        }
        else{
            input(i);
            if(i<9){
                printf("%llu\n",i-1);
                continue;
            }
            ull l=0,r=0;r--;
            if(solve1(r)<i-1){
                puts("-");
                continue;
            }
            while(r-l>1){//zkyb
                ull mid=(r>>1)+(l>>1);
                if((r&1)&&(l&1))mid++;
                if(solve1(mid)<i-1)
                    l=mid;
                else
                    r=mid;
            }
            print(r);
        }
    }
}
posted @ 2020-11-18 16:30  UCPRER  阅读(311)  评论(0编辑  收藏  举报