Lightoj1068——Investigation(数位dp)

题面

题意

给出n,m,k,求出n到m间有几个数的数字和与整个数都是k的倍数

方法

虽然k<10000,然而因为n,m小于2^31,数字和最大也就八十几,故大于85的直接输出0.
用前缀和维护一下,要求n到m,只需要求0~m - 0~n-1 即可.
dp时只需记录当前长度,数字和对k取模的结果和数对k取模的结果.

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll T,TT,n,m,k,dp[20][100][100],num[20],ten[]={1,1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000};//³¤¶È,Êý×ÖºÍÈ¡Ä£Óë×ÜÊýÈ¡Ä£

ll dfs(ll len,bool lim,ll szh,ll mod)
{
	if(!len)
	{
		if(!szh&&!mod) return 1;
		return 0;
	}
	if(!lim&&dp[len][szh][mod]!=-1) return dp[len][szh][mod];
	ll mx=9,i,j,res=0;
	if(lim) mx=num[len];
	for(i=0;i<=mx;i++)
	{
		res+=dfs(len-1,lim&&i==mx,(k+szh-i)%k,(k+mod-i*ten[len]%k)%k);
	}
	if(!lim) dp[len][szh][mod]=res;
	return res;
}

ll ys(ll u)
{
	ll i,j;
	i=0;
	while(u)
	{
		i++;
		num[i]=u%10;
		u/=10;
	}
//	for(j=1;j<=i;j++) cout<<num[j]<<" ";
//	cout<<endl;
	return dfs(i,1,0,0);
}

int main()
{
	ll i,j;
	cin>>T;
	TT=T;
	while(T--)
	{
		memset(dp,-1,sizeof(dp));
		scanf("%lld%lld%lld",&n,&m,&k);
		printf("Case %lld: ",TT-T);
		if(k>=85)
		{
			printf("0\n");
			continue;
		}
		printf("%lld\n",ys(m)-ys(n-1));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值