HDU-4734 F(X) 数位dp

数位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的三位数.所以会报错.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值