数位dp的优化
WA做法: dp数组dp[pos][now]来存pos位的数F值为now的共有多少个,但后来发现如果不在每组数据之前清空dp数组的话答案是错的.一直没有想通是为什么,如果有大佬想通了欢迎给我评论.
AC做法:借鉴了其他大佬的想法,用dp[pos][sum-now]数组存pos位的数,与sum差为sum-now的数共有多少个.这样就可以不用每次都清空dp数组,大大降低时间复杂度.
下面贴代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll A,B,T;
ll dp[15][150000];//dp[pos][now]代表第pos位和是now有多少个.
ll a[20];
ll f(ll x)
{
if(x==0) return 0;
ll ans=f(x/10);
return ans*2+(x%10);
}
ll dfs(ll pos,ll now,bool limit,ll AA)
{ if(now > AA) return 0;
if(pos == -1) return 1;
if(!limit && dp[pos][AA-now]!=-1) return dp[pos][AA-now];
ll up = limit ? a[pos] : 9;
ll tmp = 0;
for(int i = 0 ;i <= up;i++)
{
//if(now + i *(1>>pos) > AA ) break;
tmp += dfs(pos-1,now+i*(1<<pos),limit&&a[pos]==i,AA);
}
if(!limit) dp[pos][AA - now] = tmp;
return tmp;
}
ll solve(ll x,ll AA)
{ ll pos=0;
while(x)
{
a[pos++]=x%10;
x/=10;
}
return dfs(pos-1,0,true,AA);
}
int main(){
cin>>T;
memset(dp,-1,sizeof(dp));
for(ll i = 1;i<=T;i++)
{
scanf("%lld%lld",&A,&B);
ll t=0,p=0;
A = f(A);
ll ans = solve(B,A);
printf("Case #%lld: %lld\n",i,ans);
}
return 0;
}
-----------------------------这是一条莫的感情的分割线--------------------
想明白了,因为我的做法是从最高位像后最低位填数字,我在后面选数的时候应该尽量与高位无关(不知道这样能不能说明白)比如,我要填一个五位数,万位和千位都已经填完了,我还剩下百位,十位,个位要填,如果按照第一种做法,dp[3][now]的值不是-1,我直接返回,我返回的应该是,所有和是now的三位数,但是我要找的是和小于sum-now的三位数.所以会报错.