点我打开题目原文!!!
题意:
定义F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A 1 * 1 ,给定A,B,求0-B范围内X使得F(X)<=F(A).
解题思路:
这题不难,dp[i][is][Max]表示从第i位开始,is表示是否为边缘情况,Max表示F值<=Max。枚举第i位,记忆化搜索转移就可以了。这题TLE了好几发,原因是把边缘条件和非边缘条件一起记忆化了,导致每次初始化花了很多时间,其实非边缘情况与具体数据无关,只用初始化一次。这题测试组数非常多,不知道为什么能这么快过,按理说复杂挺高的!
代码:
<span style="font-size:18px;">#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<list>
#include<bitset>
//#pragma comment(linker,"/STACK:1024000000,1024000000")
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
int A,B;
int dig[10];
int dp[10][2][5000];
int fac[20];
int f(int n)
{
int ret=0;
int b=1;
while(n)
{
int r=n%10;
ret+=r*b;
b*=2;
n/=10;
}
return ret;
}
int dfs(int p,int is,int Max)
{
if(p==-1) return Max>=0;
if(dp[p][is][Max]!=-1&&!is) return dp[p][is][Max];
int up=is?dig[p]:9;
int ret=0;
for(int i=0;i<=up;i++)
{
int r=i*fac[p];
if(r<=Max) ret+=dfs(p-1,is&&i==up,Max-r);
}
return dp[p][is][Max]=ret;
}
int get()
{
int n=B;
int len=0,ret=0;
while(n)
{
dig[len++]=n%10;
n/=10;
}
ret=dfs(len-1,1,f(A));
return ret;
}
int main()
{
fac[0]=1;
for(int i=1;i<20;i++) fac[i]=fac[i-1]*2;
int t,tt=0;
scanf("%d",&t);
memset(dp,-1,sizeof dp);
while(t--)
{
scanf("%d%d",&A,&B);
int ans=0;
ans=get();
printf("Case #%d: %d\n",++tt,ans);
}
return 0;
}
</span>