链接:http://acm.hdu.edu.cn/showproblem.php?pid=4734
F(x)
Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2622 Accepted Submission(s): 969
Problem Description
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).
Input
The first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 10 9)
For each test case, there are two numbers A and B (0 <= A,B < 10 9)
Output
For every case,you should output "Case #t: " at first, without quotes. The
t is the case number starting from 1. Then output the answer.
Sample Input
3 0 100 1 10 5 100
Sample Output
Case #1: 1 Case #2: 2 Case #3: 13
题意:
问 0到b 之间有多少x符合 F(x)<=F(a)
做法:
数位dp
之前想到的状态,第二维sum 代表 这位之前 二进制数 加和是 sum, 这位及之后 有多少种数 二进制加和 + sum<=F(a)
然后超时了一发,加了个999的剪枝,200ms 过了。原因是里的dp意义和F(a)有关,所以每次要清空数组
后来看了别人的,发现原来很简单,正确的状态 sum 表示 这位及之后 有多少种数 二进制 加和<=sum
这里的dp值是固定的,每次不用清空,所以速度快很多。
第二种正确的:
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <bitset>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <string>
#include <math.h>
#include <stdlib.h>
#include <map>
#include <time.h>
using namespace std;
const int inf = 0x3f3f3f3f;
typedef int LL;
const double pi = acos(-1.0);
#define eps 1e-8
const int maxn=22;
int dig[maxn];
LL f[maxn][30000];//i位以后 二进制化后小于sum 的数字个数
LL dfs(int pos,int sum,int limit){
if (pos<0) return sum>=0;
if(sum<0) return 0;
if (!limit&&f[pos][sum]!=-1) return f[pos][sum];
LL res=0;
int last=limit?dig[pos]:9;
for (int i=0;i<=last;i++){
res+=dfs(pos-1,sum-i*(1<<pos),limit&&(i==last));
}
if (!limit) f[pos][sum]=res;
return res;
}
LL solve(LL n,LL a){
int len=0;
int fa=0;
while (n){
dig[len++]=n%10;
n/=10;
}
int tlen=0;
while(a)
{
fa+=(a%10)*(1<<tlen);
a/=10;
tlen++;
}
return dfs(len-1,fa,1);
}
int main()
{
int t;
int cas=1;
cin>>t;
memset(f,-1,sizeof f);
while(t--)
{
int a,b;
cin>>a>>b;
printf("Case #%d: ",cas++);
cout<<solve(b,a)<<endl;
}
return 0;
}
第一种:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <malloc.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;
#include <stack>
#include <queue>
#include <vector>
#include <deque>
#include <set>
#include <map>
typedef int LL;
const int maxn=10;
int dig[maxn];
LL f[maxn][5000]/* [TODO] */;//LL可能超内存
int lim;
int er[20];
int xian[20];
int jiu[20];
LL dfs(int pos ,int daxiao/* TODO */,int limit){
if (pos<0)
{
if(daxiao<=lim)
return 1;/* TODO */;
return 0;
}
if (!limit&&f[pos][daxiao]/* [TODO] */!=-1)
return f[pos][daxiao]/* [TODO] */;
if(daxiao>lim)
return 0;
if((!limit)&&pos>0&&(xian[pos]+daxiao)<=lim)
return f[pos][daxiao]=jiu[pos+1]+1;
LL res=0;
int last=limit?dig[pos]:9;
for (int i=0;i<=last;i++){
res+=dfs(pos-1,daxiao+i*er[pos]/* TODO */,limit&&(i==last));
}
if (!limit) f[pos][daxiao]/* [TODO] */=res;
return res;
}
LL solve(LL n){
memset(f,-1,sizeof f);
int len=0;
while (n){
dig[len++]=n%10;
n/=10;
}
return dfs(len-1,/* TODO */0,1);
}
LL ji(LL n)
{
int len=0;
while (n){
dig[len++]=n%10;
n/=10;
}
LL res=0;
for(int i=len-1;i>=0;i--)
{
res+=dig[i]*er[i];
}
return res;
}
int main()
{
int res=0;
res=0;
for(int i=0;i<15;i++)
{
jiu[i]=res;
res+=(res+1)*9;
}
jiu[0]=0;
er[0]=1;
for(int i=1;i<15;i++)
er[i]=er[i-1]*2;
res=0;
for(int i=0;i<15;i++)
{
res+=9*er[i];
xian[i]=res;
}
int cas=1;
int t;
scanf("%d",&t);
while(t--)
{
int a,b;
scanf("%d%d",&a,&b);
lim=ji(a);
//cout<<lim<<endl;
int ans;
/*
if(b<=a)
ans=b+1;
else*/
ans=solve(b);
/*
int num=0;
for(int i=0;i<=b;i++)
{
if(ji(i)<=lim)
num++;
}
cout<<"num "<<num<<endl;*/
printf("Case #%d: %d\n",cas++,ans);
}
return 0;
}
/*
9999999
99999999 99999999
*/