HDU 5787 K-wolf Number

题目:K-wolf Number

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5787

题意:给出L,R,K,求L到R之间有多少数满足:(10进制下)任意两个相等的数字至少相差K位。(1<=L<=R<=1e18,2<=k<=5)。

思路:

  dp[i][j]:表示i 位且前面k位数为j 的情况有多少种,为了细节处理方便,dp数组形式改为:dp[pos][p1][p2][p3][p4]表示pos位,p1、p2、p3、p4是前面四位数字。初始化为10、10、10、10表示前导0。

  采取记忆化搜索的姿势,dfs(pos,p1,p2,p3,p4,flag),flag=1表示这一位数有限制(不是题目要求中的限制,而是比如1234,那么第一位确定为1时,第二位最高只能2的限制。)具体在代码解释。

  有点坑的是我尝试用dp[pos][pre]形式解的时候,第二维不能是1万,应该要10万,不然pre%1000*10+i,原本的1023会变成023i,会被误认为23i,就少判断了一个是否等于0。

AC代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 typedef long long LL;
 4 LL dp[20][11][11][11][11];
 5 int bt[20],bo;
 6 LL L,R;
 7 int K;
 8 bool check(int p1,int p2,int p3,int p4,int now)  //根据K进行判断i是否可以和p1、p2、p3、p4共存
 9 {
10   if(K==2) return now!=p4;
11   else if(K==3) return now!=p3 && now!=p4;
12   else if(K==4) return now!=p2 && now!=p3 && now!=p4;
13   else return now!=p1 && now!=p2 && now!=p3 && now!=p4;
14 }
15 LL dfs(int pos,int p1,int p2,int p3,int p4,bool flag)
16 {
17   if(pos==-1) return p4!=10;  //结束判断,如果p4还等于10,那说明全是0,在这里,我规定0不满足条件。
18   if(!flag && dp[pos][p1][p2][p3][p4]!=-1) return dp[pos][p1][p2][p3][p4];  //如果以前存过值,直接取。
19   // 存取值都在flag=0的情况下进行,也就是接下来pos位无限制(只有题目限制)的条件下进行。
20   int limit= flag?bt[pos]:9;  //limit表示这一位最高可以取到多少,没有限制就是9,有限制就是原数的这一位数字
21   LL ret=0;
22   for(int i=0;i<=limit;i++)
23   {
24     //如果p4还等于10表示前面全是前导0,i又取0,那么pos位还是前导0。
25     if(i==0 && p4==10) ret+=dfs(pos-1,p1,p2,p3,10,flag && i==limit);
26     else if(check(p1,p2,p3,p4,i)) ret+=dfs(pos-1,p2,p3,p4,i,flag && i==limit); //判断i是否可以和前面的数字共存。
27   }
28   if(!flag) dp[pos][p1][p2][p3][p4]=ret; //存值
29   return ret;
30 }
31 LL solve(LL x)
32 {
33   if(x<=0) return 0;
34   bo=0;
35   while(x)
36   {
37     bt[bo++]=x%10;
38     x/=10;
39   }
40   return dfs(bo-1,10,10,10,10,1);
41 }
42 int main()
43 {
44   while(scanf("%I64d%I64d%d",&L,&R,&K)!=EOF)
45   {
46     memset(dp,-1,sizeof(dp));
47     printf("%I64d\n",solve(R)-solve(L-1));
48   }
49   return 0;
50 }
时间: 2024-08-10 23:16:00

HDU 5787 K-wolf Number的相关文章

hdu 5787 K-wolf Number 数位dp

数位DP 神模板 详解 为了方便自己参看,我把代码复制过来吧 // pos = 当前处理的位置(一般从高位到低位) // pre = 上一个位的数字(更高的那一位) // status = 要达到的状态,如果为1则可以认为找到了答案,到时候用来返回, // 给计数器+1. // limit = 是否受限,也即当前处理这位能否随便取值.如567,当前处理6这位, // 如果前面取的是4,则当前这位可以取0-9.如果前面取的5,那么当前 // 这位就不能随便取,不然会超出这个数的范围,所以如果前面取

hdu 1394 Minimum Inversion Number(线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 10853    Accepted Submission(s): 6676 Problem Description The inversion number of a given number sequence a1, a2, ..., a

HDU 1394 Minimum Inversion Number (数据结构-线段树)

Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 9514    Accepted Submission(s): 5860 Problem Description The inversion number of a given number sequence a1, a2, ..., an

【线段树】HDU 1394 Minimum Inversion Number

minimum inversion number:最小逆序数 Minimum Inversion NumberTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 9367    Accepted Submission(s): 5754 Problem Description The inversion number of a given nu

hdu 5623 KK&#39;s Number(dp)

问题描述 我们可爱的KK有一个有趣的数学游戏:这个游戏需要两个人,有N\left(1\leq N\leq 5*{10}^{4} \right)N(1≤N≤5∗10?4??)个数,每次KK都会先拿数.每次可以拿任意多个数,直到NN个数被拿完.每次获得的得分为取的数中的最小值,KK和对手的策略都是尽可能使得自己的得分减去对手的得分更大.在这样的情况下,最终KK的得分减去对手的得分会是多少? 输入描述 第一行一个数T\left( 1\leq T\leq 10\right)T(1≤T≤10),表示数据组

hdu 1394 Minimum Inversion Number

题目链接:hdu 1394 Minimum Inversion Number 该题是求最小逆序对的扩展.可以使用树状数组来实现.对于$n$个数的序列$A$,其第$i$个数($i\in [0,n)$)的逆序数$r_i$可以表示为它的角标$i$减去在它之前且不大于它的数的个数.例如对序列A = {1,3,5,9,0,8,5,7,4,2}中的数,A[8] = 4.其逆序数$r_8 = 8 - 3 = 5$,第二个3表示三个在它前面且比它小的数:{1,3,0}.从而我们可以得到第$i$个数的逆序数公式:

hdu 1394 Minimum Inversion Number (裸树状数组 求逆序数)

题目链接 题意: 给一个n个数的序列a1, a2, ..., an ,这些数的范围是0-n-1, 可以把前面m个数移动到后面去,形成新序列:a1, a2, ..., an-1, an (where m = 0 - the initial seqence)a2, a3, ..., an, a1 (where m = 1)a3, a4, ..., an, a1, a2 (where m = 2)...an, a1, a2, ..., an-1 (where m = n-1)求这些序列中,逆序数最少的

HDU 1394 Minimum Inversion Number(线段树求逆序数)

题目地址:HDU 1394 这题可以用线段树来求逆序数. 这题的维护信息为每个数是否已经出现.每次输入后,都从该点的值到n-1进行查询,每次发现出现了一个数,由于是从该数的后面开始找的,这个数肯定是比该数大的.那就是一对逆序数,然后逆序数+1.最后求完所有的逆序数之后,剩下的就可以递推出来了.因为假如目前的第一个数是x,那当把他放到最后面的时候,少的逆序数是本来后面比他小的数的个数.多的逆序数就是放到后面后前面比他大的数的个数.因为所有数都是从0到n-1.所以比他小的数就是x,比他大的数就是n-

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对)

HDU 1394 Minimum Inversion Number(线段树求最小逆序数对) ACM 题目地址:HDU 1394 Minimum Inversion Number 题意: 给一个序列由[1,N]构成,可以通过旋转把第一个移动到最后一个. 问旋转后最小的逆序数对. 分析: 注意,序列是由[1,N]构成的,我们模拟下旋转,总的逆序数对会有规律的变化. 求出初始的逆序数对再循环一遍就行了. 至于求逆序数对,我以前用归并排序解过这道题:点这里. 不过由于数据范围是5000,所以完全可以用线

hdu 6216 A Cubic number and A Cubic Number【数学】

hdu 6216 A Cubic number and A Cubic Number 题意:判断一个素数是否是两个立方数之差,就是验差分. 题解:只有相邻两立方数之差才可能,,因为x^3-y^3=(x-y)(x^2+xy+y^2),看(x-y),就能很快想到不相邻的立方数之差是不可能是素数的:),,然后把y=x+1代入,得:p=3x^2+3x+1,所以可得判断条件为:①p-1必须能被3整除:②(p-1)/3必须能表示为两个相邻整数之积. 1 #include<iostream> 2 #incl