思路:
这个数位卡我时间又卡我空间,时间和空间限制都很小,时间就500ms。
我想通过再开一个数组记录访问过的状态是否与本次输入有关,来避免每次都要初始化数组,同时又不用多开一维(
会爆空间,
),即便如此还是会超时,因为它有
组数据,所以如果每次都重新算一遍的话,铁定超时,与是否初始化的时间开销无关。
然后参考了一位博主的博客,我数位白学了。
对于我解这题固有的思路而言,"判断是否"并没有体现在
的状态中,所以这样产生的
值是依赖于
的,仅能应用在当前数据上,如果数据量大就会
。
但是完全可以采取更优的方案消除状态与输入的相关性。(无论你取什么值,
都是一个常量,永远不会改变。)
以前也有过消除状态与输入的相关性,但都是模板刚好就能完成或者没有多组输入,而这题的第二维需要存储第
位到最低位最多还能够增加的
值,留意当状态与输入相关时怎么去消除这个性质。
我居然因为没有初始化卡了几十分钟,菜~
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include <vector>
#include<map>
#include<set>
#include<utility>
using namespace std;
typedef long long ll;
inline ll read() {
ll s = 0, w = 1;
char ch = getchar();
while (ch < 48 || ch > 57) {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= 48 && ch <= 57)
s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
return s * w;
}
int dp[11][4600];
int digit[11],all;
int dfs(int len,int sum,bool limit) {
if(sum<0) return 0;
if(!len) {
return 1;
}
if(!limit&&dp[len][sum]!=-1) return dp[len][sum];
int endi=(limit?digit[len]:9);
int ans=0;
for(int i=0;i<=endi;++i) {
ans+=dfs(len-1,sum-i*(1<<(len-1)),limit&&i==endi);
}
if(!limit) dp[len][sum]=ans;
return ans;
}
int solve(ll x) {
int len=0;
while(x) {
digit[++len]=x%10;
x/=10;
}
return dfs(len,all,true);
}
void change(int n) {
all=0;
int tmp=1;
while(n) {
all+=(n%10)*tmp;
tmp<<=1;
n/=10;
}
}
int main() {
int t=read(),cas=0,r,n;
memset(dp,-1,sizeof dp);
while(t--) {
cas+=1;
n=read(),r=read();
change(n);
printf("Case #%d: %d\n",cas,solve(r));
}
return 0;
} 
京公网安备 11010502036488号