数位dp变相 [HDU-5456]


题意:给你n个火柴 让你凑成a-b=c的形式,不包括前导0,问总共有多少个方案数(mod上m)。
思路:真的想不出来,太妙了,先把a-b=c变形成a=b+c,然后从低位往高位枚举每位填的数,dp状态定义成f[i][f1][f2][flow] (只剩下i根火柴,b是否填完,c是否填完,是否有进位的方案数),终止条件就是b和c都填完了,看看是否有进位。很妙,每次火柴数量减去要填的数量,a的数字可以算出来,是(flow+i+j)%10。
代码:

#include
#include
using namespace std;
typedef long long ll;
const int N=510;
int stk[10]={
     6,2,5,5,4,5,6,3,7,6};
ll f[N][2][2][2]; //将a-b=c 转化为 a=b+c ,状态含义为只剩下i根火柴 b和c是否枚举完,是否有进位
int n,m;
ll dfs(int num,bool f1,bool f2,bool flow)
{
     
	if(num<0)	return 0;
	ll &v = f[num][f1][f2][flow];
	if(~v)	return f[num][f1][f2][flow];
	if(f1 && f2)	return flow*2==num;
	ll ans=0;
	if(!f1 && f2)
	{
     
		for(int i=0;i<=9;i++)
		{
     
			int cost=stk[i] + stk[(i+flow)%10];
			ans= (ans+dfs(num-cost,f1,f2,(flow+i)/10))%m;
			if(i)
				ans= (ans + dfs(num-cost,1,f2,(flow+i)/10))%m;
		}
	}
	if(f1 && !f2)
	{
     
		for(int i=0;i<=9;i++)
		{
     
			int cost=stk[i] + stk[(i+flow)%10];
			ans=(ans + dfs(num-cost,f1,f2,(flow+i)/10))%m;
			if(i)
				ans= (ans +dfs(num-cost,f1,1,(flow+i)/10))%m;
		}
	}
	if(!f1 && !f2)
	{
     
		for(int i=0;i<=9;i++)
			for(int j=0;j<=9;j++)
			{
     
				int cost=stk[i]+stk[j]+stk[(i+j+flow)%10];
				ans = (ans + dfs(num-cost,f1,f2,(flow+i+j)/10))% m ;
				if(i)
					ans = ( ans + dfs(num-cost,1,f2,(flow+i+j)/10))%m;
				if(j)
					ans = ( ans + dfs(num-cost,f1,1,(flow+i+j)/10))%m;
				if(i&&j)
					ans = (ans + dfs(num-cost,1,1,(flow+i+j)/10)) % m;
			}
	}
	return v = ans;
}
int main()
{
     
	int cnt=0;
	int t;
	cin>>t;
	while(t--)
	{
     
		memset(f,-1,sizeof f);		
		cin>>n>>m;
		cout<<"Case #"<<++cnt<<": "<<dfs(n-3,0,0,0)<<endl;
	}
	return 0;
}

你可能感兴趣的:(dp,icpc,数位dp)