一,题意:
该题定义了一个函数 : F(x)=An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 1。
现在他给定两个数,A,B,要求你求出在区间[0,B] 有多少个x ,使得F(x)<=F(A)。
二,解析:
该题主要应用了,数位dp的思想+记录状态dp的思想。
1,数位dp思想主要数是用数组来存储数,通过对数组每一位进行枚举(0,1,2,,,9),
到达便利区间[0,N]内所有数的目的
例如: 比456小的数,可以这么考虑:
这样就可以遍历[0,456]区间所有的数。
2,记录状态思想,记录下程序已走过的路,当在次走相同的路时直接返回。
至于这么判断是否走同一条路是一般是通过函数参数值,如果用同样的参数去调用同一个函数则所走的路必然是相同的。
所以dp[i][j],数组下标i,j一般表示的就是调用函数的参数。
三:代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;
int T,N,M;
int bit[15];
int Max[15];
int dp[15][200000];
//dp[len][sum]表示长度为len且权值不大于sum的数的个数。
int DFS(int len,int sum,bool Big)
{//len所搜索到的长度,sum是F[N]剩余的部分,big标记前驱是不是最大数
if(sum<0)
return 0;
if(len<=0)
return 1;//两个边界
if(!Big&&dp[len][sum]!=-1)
return dp[len][sum];//记录状态
int bian=9;
if(Big)//第len位的边界
bian=Max[len];
int key=0;
for(int i=0;i<=bian;i++)
key+=DFS(len-1,sum-(i*bit[len]),Big&&(i==bian));
if(!Big)
dp[len][sum]=key;
return key;
}
int solve(int n,int m)
{
int key=0;
int len=1;
while(n)
{//计算F[N]
key=key+(n%10)*bit[len];
len++;
n=n/10;
}
len=0;
while(m)
{//分解M
Max[++len]=m%10;
m=m/10;
}
return DFS(len,key,true);
}
int main()
{
bit[1]=1;
for(int i=2;i<=11;i++)
bit[i]=bit[i-1]*2;
memset(dp,-1,sizeof(dp));
scanf("%d",&T);
for(int k=1;k<=T;k++)
{
scanf("%d%d",&N,&M);
printf("Case #%d: %d\n",k,solve(N,M));
}
return 0;
}