K

K - Number with Bachelors 数位dp + 思维

题目大意:

定义一种数 Y:表示把Y分解,分解出来的每一位没有重复的,例如:101就不是Y这种数,123是Y这种数

有n次查询,有两种查询操作:

  • 0 后面给两个数a,b,求a到b之间的Y这种数
  • 1 后面给定x,求第x大的Y数

有两种不同进制的询问,十进制和16进制

题解:

很明显第一个种操作就是一个数位dp,第二种操作想清楚可以发现是一个二分+数位dp

这个题目一定要注意进制之间的转化,建议写一个输入函数和输出函数,这样就可以统一处理10进制和16进制了。

最后还要注意的是按照正常的数位dp(也就是我的这种写法) d 1 1这个样例会TLE,具体原因可以输入一下二分的mid就可以发现了,所以要把 1 这种操作的 x == 1特判掉,还有就是注意0这种操作的a可能是0,所以也要判断一下。

细节比较多。

#include <bits/stdc++.h>
using namespace std;
const int maxn = (1<<16) + 10;
typedef unsigned long long ull;
ull dp[2][22][maxn];
int type,a[100];
 
ull dfs(int pos,int sta,int limit){
    if(pos==-1) return 1;
    int ty = (type==10)?0:1;
    if(dp[ty][pos][sta]!=-1&&!limit) return dp[ty][pos][sta];
    int up = limit?a[pos]:type - 1;
    ull ans = 0;
    for(int i=0;i<=up;i++){
        if((sta>>i)&1) continue;
        if(sta==0&&i==0) ans+=dfs(pos-1,sta,limit&&i==up);
        else ans+=dfs(pos-1,sta|(1<<i),limit&&i==up);
    }
    if(!limit) dp[ty][pos][sta] = ans;
    // printf("pos = %d sta = %d limit = %d ans = %llu
", pos,sta,limit,ans);
    return ans;
}
 
ull solve(ull x){
    int pos = 0;
    while(x){
        a[pos++] = x%type;
        x/=type;
    }
    return dfs(pos-1,0,true);
}
 
void input(ull &x){
    x = 0;
    char s[22];
    scanf("%s",s+1);
    int len = strlen(s+1);
    for(int i=1;i<=len;i++) {
        if(s[i]<='9'&&s[i]>='0') x = x * type + s[i] - '0';
        else x = x * type + s[i] - 'a' + 10;
    }
}
void print(ull x){
    if(x==0){
        printf("0
");
        return ;
    }
    if(type == 10) printf("%llu
", x);
    else{
        vector<int>ans;
        while(x){
            int p = x % type;
            x/=type;
            ans.push_back(p);
        }
        for(int i=ans.size()-1;i>=0;i--) {
            if(ans[i]>=10) printf("%c", ans[i] - 10 + 'a');
            else printf("%c", ans[i]+'0');
        }
        printf("
");
    }
}
void test(){
    int t;
    scanf("%d",&t);
    while(t--){
        int x;
        scanf("%d%d",&x,&type);
        printf("%llu",solve(x));
    }
}
int main(){
    memset(dp,-1,sizeof(dp));
    // test();
    int T;
    scanf("%d",&T);
    while(T--){
        char op[10];
        scanf("%s",op);
        if(op[0]=='d') type = 10;
        else type = 16;
        int flag;
        scanf("%d",&flag);
        if(!flag){
            ull a,b;
            input(a),input(b);
            // printf("ss a = %llu b = %llu
", a,b);
            ull ans = solve(b);
            if(a>0) ans-=solve(a - 1);
            print(ans);
        }
        else{
            ull x;
            input(x);
            if(x<10){
                printf("%llu
", x - 1);
                continue;
            }
            ull l = 0,r = 0,ans = 0;r--;
            if(solve(r)<x){
                printf("-
");
                continue;
            }
            while(l<=r){
                ull mid = l + (r - l) / 2;
                if(solve(mid)>=x) r = mid - 1,ans = mid;
                else l = mid + 1;
            }
            print(ans);
        }
    }
}
原文地址:https://www.cnblogs.com/EchoZQN/p/14045054.html