zoukankan      html  css  js  c++  java
  • ZOJ 3962

    就是统计1~n中出现的各个数字的次数,当然是在16进制下。

    不过有个区间问题的小技巧,统计从 [x,y] 可以转换成 从 [1,y] 减去 [1,x-1]。

    不过要分类讨论一下,因为有可能会出现溢出,从ffffffff +1 得到 00000000 就是溢出了。

    因为 n < 1e9 所以只会溢出一次。

     // 290ms

    #include<cstdio>
    #include<cmath>
    #include<cctype>
    
    const int cost[] = {6,2,5,5,4,5,6,3,
                        7,6,6,5,4,5,5,4};
    
    long long solve(long long n, int k) {
        long long i = 1;   // 位数
        long long cnt = 0;
        long long low = 0;
        long long tmp = n;
        while(n) {
            long long t = n % 16;
            n /= 16;
            low = tmp % i;
            if(t < k) {
                cnt += n*i;
            } else if(t > k) {
                cnt += (1+n)*i;
            } else {
                cnt += n*i;
                cnt += low+1;
            }
            i *= 16;
        }
        return cnt;
    }
    int Hex(char c){
        if(isdigit(c))
            return c-'0';
        return c - 'A' + 10;
    }
    int main() {
        int t;
        scanf("%d",&t);
        for(int i=0;i<t;i++){
            long long n;
            long long x=0;
            char str[15];
            scanf("%lld%s",&n,str);
            for(int i=0;i<8;i++)
                x = (x<<4) + Hex(str[i]);
            long long cnt = 0;
            long long ans = 0;
    
            if((n-1)+x <= 4294967295ll){ // 没有溢出
                long long tmp;
                for(int i=1;i<16;i++){
                    tmp = solve((n-1ll)+x,i);
                    cnt += tmp;
                    ans += tmp*cost[i];
                }
                for(int i=1;i<16;i++){
                    tmp = solve(x-1,i);
                    cnt -= tmp;
                    ans -= tmp*cost[i];
                }
                ans += (n*8-cnt)*cost[0];
            }else {
                long long tmp;
                for(int i=1;i<16;i++){
                    tmp = solve(4294967295ll,i);
                    cnt += tmp;
                    ans += tmp*cost[i];
                }
                for(int i=1;i<16;i++){
                    tmp = solve(x-1,i);
                    cnt -= tmp;
                    ans -= tmp*cost[i];
                }
                for(int i=1;i<16;i++){
                    tmp = solve((n-2ll)+x-4294967295ll,i);
                    cnt += tmp;
                    ans += tmp*cost[i];
                }
                ans += (n*8-cnt)*cost[0];
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

    搜了一下题解发现可以用数位dp做。。

    当时倒是也想到了数位dp但是因为做过的都是不定长的,所以就没有想到可以定长为8。

    // 250ms

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<cctype>
    
    int digit[16];
    long long dp[10][100];
    const int cost[] = {6,2,5,5,4,5,6,3,
                        7,6,6,5,4,5,5,4};
    
    long long dfs(int d,int sum,bool shangxian){
        if(d == 0)return sum;
        if(!shangxian && dp[d][sum] != -1)
            return dp[d][sum];
        int maxn = shangxian?digit[d]:15;
        long long tmp = 0;
        for(int i=0;i<=maxn;i++){
            tmp += dfs(d-1,sum+cost[i],shangxian && i==maxn);
        }
        return shangxian?tmp:dp[d][sum]=tmp;
    }
    long long solve(long long x){
        int k = 0;
        if(x<0)return 0;
        memset(digit,0,sizeof(digit));
        while(x){
            digit[++k] = x % 16;
            x /= 16;
        }
        return dfs(8,0,1);
    }
    int Hex(char c){
        if(isdigit(c))
            return c-'0';
        return c - 'A' + 10;
    }
    int main() {
        int t;
        memset(dp,-1,sizeof(dp));
        scanf("%d",&t);
        while(t--){
            long long n;
            long long x=0;
            char str[15];
            scanf("%lld%s",&n,str);
            for(int i=0;i<8;i++)
                x = (x<<4) + Hex(str[i]);
            // 4294967295ll
            if(x+n-1 <= 4294967295ll)
                printf("%lld
    ",solve(x+n-1)-solve(x-1));
            else
                printf("%lld
    ",
                       solve(4294967295ll)-solve(x-1)+solve(x+n-2-4294967295ll));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    11. 盛最多水的容器
    820. 单词的压缩编码
    72. 编辑距离
    10041-回文数
    第六章-希尔排序和堆排序
    第六章-快速排序、合并排序
    第六章 排序-冒泡,选择,插入排序
    第四章-二叉树的运用-AVL平衡二叉树
    第四章-二叉树的运用-排序二叉树的代码
    第四章-二叉树的代码 、二叉树前序中序后序遍历、及运用
  • 原文地址:https://www.cnblogs.com/kongbb/p/10702004.html
Copyright © 2011-2022 走看看