洛谷P4127 [AHOI2009]同类分布

数位$dp$

这里我们首先考虑一种做法,就是记录$f[pos][sum][num]$表示当前是第$pos$位,总的数字和为$sum$,现在的数字是$num$,那么我们看看下面一行小字,输入的数位数小于等于$1000$,????一脸懵逼,开个么大的$f$数组??于是我们优化一下,我们枚举模数就行了,具体看代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define N 21
using namespace std;
int val[N];
ll l,r,mod;
ll f[N][207][207];
ll Dfs(int pos,ll sum,ll num,bool limit,bool lead)
{
	if(!pos&!sum)
		return 0;
	if(!pos)
	{
		if(sum==mod&&!num)
			return 1;
		else
			return 0;	
	}
	
	if(!limit&&!lead&&f[pos][sum][num]!=-1)
		return f[pos][sum][num];
	int maxn=limit?val[pos]:9;
	ll ans=0;
	for(int i=0;i<=maxn;++i)
		ans+=Dfs(pos-1,sum+i,(num*10+i)%mod,limit&&(i==maxn),(lead&&!i));
	if(!limit&&!lead)
		f[pos][sum][num]=ans;
	return ans;
}
ll Get(ll x)
{
	int len=0;
	while(x)
	{
		val[++len]=x%10;
		x/=10;
	}
	ll ans=0;
	for(mod=1;mod<=9*len;++mod)
	{
		memset(f,-1,sizeof(f));
		ans+=Dfs(len,0,0,1,1);	
	}
	return ans;
}
int main()
{
	//memset(f,-1,sizeof(f));
	scanf("%lld%lld",&l,&r);
	printf("%lld",Get(r)-Get(l-1));
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/yexinqwq/p/10235334.html
今日推荐