For a decimal number x with n digits (A
nA
n-1A
n-2 ... A
2A
1), we define its weight as F(x) = A
n * 2
n-1 + A
n-1 * 2
n-2 + ... + A
2 * 2 + A
1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there between 0 and B, inclusive, whose weight is no more than F(A).
For each test case, there are two numbers A and B (0 <= A,B < 10 9)
3 0 100 1 10 5 100
Case #1: 1 Case #2: 2 Case #3: 13
【题解】
大致题意:给一个区间,求这个区间内不大于F(x)并且不大于y的数的个数。
首先得知道,这个F(x)公式算出来的值最大值不会超过5000,所以数组不用开太大。
然后就是判断了,基本思路都是套模板,递归部分就是每次用上限减去组成的数,如果是正的就加1,否则继续找, 直到全部组合完了。
【AC代码】
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int dp[12][5000];
int num[12];
int m,n;
int F(int x)//求上限
{
int p=1;
int ans=0;
while(x)
{
ans+=(x%10)*p;
x/=10;
p<<=1;
}
return ans;
}
int dfs(int pos,int value,int limit)//value 为上限值减去上一位组成的数的余数
{
if(value<0) return 0;//如果余数提前小于0了 直接退
if(pos<0) return value>=0;//余数大于0 符合条件 返回1
if(!limit && dp[pos][value]!=-1) return dp[pos][value];
int ans=0;
int endi= limit ? num[pos]:9;
for(int i=0;i<=endi;++i)
{
ans+=dfs(pos-1,value-i*(1<<pos),limit&&i==endi);
}
if(!limit) dp[pos][value]=ans;
return ans;
}
int solve(int x)
{
int len=0;
while(x)
{
num[len++]=x%10;
x/=10;
}
return dfs(len-1,F(m),1);
}
int main()
{
int t;
memset(dp,-1,sizeof(dp));
scanf("%d",&t);
for(int i=1;i<=t;++i)
{
scanf("%d%d",&m,&n);
printf("Case #%d: %d\n",i,solve(n));
}
return 0;
}