这里是题目链接 F(x) [Submit]
F(x)Time Limit: 1000/500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 11388 Accepted Submission(s): 4417 Problem Description For a decimal number x with n digits (AnAn-1An-2 ... A2A1), we define its weight as F(x) = An * 2n-1 + An-1 * 2n-2 + ... + A2 * 2 + A1 * 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. 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 |
题意:定义f(x) = a(n)*2^(n-1)+a(n-1)*2(n-2)+…a(2)*2+a(1)*1,a(i)表示十进制数x中第i位的数字。
题目给出a,b,求出0~b有多少个不大于f(a)的数。
这真是一道奇怪的题目,公式已经告诉你了,但是就是不好做,看着公式去枚举吗?你想啥呢?请看Time Limit 500ms!!!
看到这里我也是惊了,才500ms还要跑多组样例。。。
这就要谨慎的发挥我们记忆化搜索的神威了。而且还要是那种各个样例之间通用的记忆化dp数组
刚开始想着dp[pos][sum]不就完事了,sum记录从len到pos位上数字累计的权重
我们定义dp[pos][sum]的话,但是我们这T组数据……
每组数据只要B有变化,由于sum是从最高位往下累加权重,它跟B有密切关系(B的长度len即为最高位)
那么dp数组就要重新memset(dp,-1,sizeof(dp)),这样才不会出错;
但是你不断地memset的话500ms可定扛不住,那就只能换一种方法喽
那么如果sum代表从第1位到第pos位最多还能累加起多少权重,那么它就和B没什么关系
我们就不需要在输入每组数据后都重新将DP数组全部重置为-1
这就是这道题目最神奇的地方。。。
这种思维方式可以记下来,说不定什么时候就能用的着
还有就是dp数组的大小,开小了就会被TLE,难受
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=20;
int dp[mm][5000];
int a[mm],b[mm];
int xx;
int dfs(int pos,int sum,int limit){
if(pos<0)return 1;
if(!limit&&~dp[pos][sum])
return dp[pos][sum];
int res=0;
int up=limit?b[pos]:9;
for(int i=0;i<=up;i++){
if(sum<i*(1<<pos))break;
int temp=sum-i*(1<<pos);
res+=dfs(pos-1,temp,limit&&i==b[pos]);
}
if(!limit)dp[pos][sum]=res;
return res;
}
int get(int x){
int cnt=0;
int ans=0;
while(x){
a[cnt++]=x%10;
x/=10;
}
for(int i=0;i<cnt;i++){
ans+=a[i]*(1<<i);
}
return ans;
}
int solve(int x){
int cnt=0;
while(x){
b[cnt++]=x%10;
x/=10;
}
return dfs(cnt-1,xx,1);
}
int main()
{
int t;
scanf("%d",&t);
int x,y,test=1;
mem(dp,-1);
while(t--){
scanf("%d%d",&x,&y);
xx=get(x);
int res=solve(y);
printf("Case #%d: %d\n",test++,res);
}
return 0;
}