zoukankan      html  css  js  c++  java
  • HDU 3943 K-th Nya Number(数位DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3943

    题目大意:求出区间 (P,Q] 中找到第K个满足条件的数,条件是该数包含X个4和Y个7

    Sample Input
    1
    38 400 1 1
    10
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    Sample Output
    Case #1:
    47
    74
    147
    174
    247
    274
    347
    374
    Nya!
    Nya!

    分析一:

      先预处理dp[i][j][k]表示第 i 位有 j 个4和 k 个7的数量。之后就可以通过高位开始枚举,求出区间内有多少个规定的数,如果询问大于总数,则输出“Nya!”

      之后找第k大的数:首先可以确定出位数,dp[i][x][y]表示 i 位时的满足数,那么大于dp[len-1][x][y],而小于dp[len][x][y],len表示目标位数。

      确认了位数之后,依然从高位开始。比如说高位首先是0,而dp[len-1][x][y]小于k,说明0开头的目标小于所求,继续往后找,把之前的删掉

      有点意思

    代码如下:

      1 # include<iostream>
      2 # include<cstdio>
      3 # include<cstring>
      4 # define LL __int64
      5 using namespace std;
      6 
      7 LL dp[25][25][25]; //dp[i][j][k]表示i位的数,有j个4,k个7的数量
      8 LL l,r;
      9 int x,y;
     10 
     11 void init()
     12 {
     13     int i,j,k;
     14     memset(dp,0,sizeof(dp));
     15     dp[0][0][0] = 1;
     16     for(i=1; i<=21; i++)
     17         for(j=0; j<i; j++)
     18             for(k=0; k+j<i; k++)
     19             {
     20                 dp[i][j][k+1] += dp[i-1][j][k];
     21                 dp[i][j+1][k] += dp[i-1][j][k];
     22                 dp[i][j][k] += dp[i-1][j][k]*8; //在高位上加除4、7以外的8个数字
     23             }
     24 }
     25 
     26 LL get_count(LL n)  
     27 {
     28     int bit[25],len=0;
     29     while(n)
     30     {
     31         bit[++len] = n%10;
     32         n /= 10;
     33     }
     34     LL ans = 0;
     35     int cx=x, cy=y;
     36     for(int i=len; i; i--)  //从高位开始枚举
     37     {   
     38         for(int j=0; j<bit[i]; j++)
     39             if(j==4)
     40             {
     41                 if(cx)
     42                     ans += dp[i-1][cx-1][cy];
     43             }
     44             else if(j==7)
     45             {
     46                 if(cy)
     47                     ans += dp[i-1][cx][cy-1];
     48             }
     49             else
     50                 ans += dp[i-1][cx][cy];
     51         if(bit[i]==4)
     52             cx--;
     53         if(bit[i]==7)
     54             cy--;
     55         //如果高位出现的4、7的数量已经超过所求,则退出
     56         if(cx<0 || cy<0)
     57             break;
     58     }
     59     return ans;
     60 }
     61 
     62 LL solve(LL k)
     63 {
     64     int len = 1;
     65     while(1)
     66     {   
     67         //找到目标长度
     68         if(dp[len-1][x][y]<k && dp[len][x][y]>=k)
     69             break;
     70         len++;
     71     }
     72     LL ret = 0;
     73     int cx=x, cy=y;
     74     for(int i=len; i; i--)
     75     {
     76         //从高位开始枚举
     77         for(int j=0; j<10; j++)
     78         {
     79             int tx = cx,ty=cy;
     80             if(j==4)
     81             {
     82                 tx--;
     83                 if(tx<0)
     84                     continue;
     85             }
     86             if(j==7)
     87             {
     88                 ty--;
     89                 if(ty<0)
     90                     continue;
     91             }
     92             if(dp[i-1][tx][ty] >= k)
     93             {
     94                 ret = ret*10+j;
     95                 cx=tx;
     96                 cy=ty;
     97                 break;
     98             }
     99             k -= dp[i-1][tx][ty];
    100         }
    101     }
    102     return ret;
    103 }
    104 
    105 int main()
    106 {
    107     init();
    108     int T,cas;
    109     scanf("%d",&T);
    110     for(cas=1; cas<=T; cas++)
    111     {
    112         scanf("%I64d%I64d%d%d",&l,&r,&x,&y);
    113         LL a=get_count(r+1);
    114         LL b=get_count(l+1);    //注意左开区间
    115         int n;
    116         scanf("%d",&n);
    117         printf("Case #%d:
    ",cas);
    118         while(n--)
    119         {
    120             LL k;
    121             scanf("%I64d",&k);
    122             if(k > a-b)
    123                 puts("Nya!");
    124             else
    125                 printf("%I64d
    ",solve(k+b));
    126         }
    127     }
    128     return 0;
    129 }

     分析二:

      将solve() 函数改成二分写法,答案更简洁

     1 LL solve(LL k)
     2 {
     3     LL mid,ans=-1,ret,left=l,right=r;
     4     while(left<=right)
     5     {
     6         mid = (left+right)>>1;
     7         ret = get_count(mid+1);
     8         if(ret>=k)
     9         {
    10             ans =mid;
    11             right = mid-1;
    12         }
    13         else
    14         left=mid + 1;
    15     }
    16     return ans;
    17 }
  • 相关阅读:
    安全测试的概述和用例设计
    性能测试(四)常见调优
    性能测试(三)常见的性能测试缺陷
    Jmeter(七)六种参数化的方式
    Jmeter(六)所有的断言
    接口测试的问题解答
    ES学习
    flutter 之BottomNavigationBar属性
    flutter StaggeredGridView.countBuilder 上方取消空白
    flutter升级、回退到指定版本---mac版
  • 原文地址:https://www.cnblogs.com/acm-bingzi/p/3339980.html
Copyright © 2011-2022 走看看