动态规划六

复健Day4

动态规划(六)数位DP

数位DP的特点:求某个区间[l,r]内,满足某种性质的数的个数

技巧一:类似前缀和的思想,转化为[0,r][0,l1]求解

技巧二:从高位到低类填数,分类讨论;

比如比R小的数的个数,对于数R=anan1an,如果某一位填了0ai,则后面每一位都可填09的任意数,如果填ai,则继续讨论下一位(这样才不会大于R)

1.数字游戏

f[i][j]表示一共有i位,且最高位数字为j的不降数个数

f[i][j]=k=j9f[i1][k]

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 12
using namespace std;

int a[maxn],f[maxn][maxn];

void init()
{
	for(int i=0;i<=9;i++) f[1][i]=1;
	for(int i=2;i<=maxn;i++)
	{
		for(int j=0;j<=9;j++)
		{
			for(int k=j;k<=9;k++) f[i][j]+=f[i-1][k];
		}
	}
}

int dp(int n)
{
	if(!n) return 1;//特判,0也是一个不降数 
	int cnt=0;
	while(n) a[++cnt]=n%10,n/=10;
	int res=0,last=0;
	for(int i=cnt;i>=1;--i)
	{
		int now=a[i];
		for(int j=last;j<now;j++) res+=f[i][j];
		if(now<last) break;
		last=now;
		if(i==1) res++;//就是0也是一个不降数 
	}
	return res;
}

int main()
{
	init();
	int l,r;
	while(cin>>l>>r)
	{
		cout<<dp(r)-dp(l-1)<<endl;
	}
	return 0;
}

2.windy

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define maxn 10
using namespace std;

int f[maxn][maxn];

void init()
{
	for(int i=0;i<=9;i++) f[1][i]=1;
	for(int i=2;i<=10;i++)
	{
		for(int j=0;j<=9;j++)
		{
			for(int k=0;k<=9;k++)
			{
				if(abs(k-j)>=2) f[i][j]+=f[i-1][k];
			}
		}
	}
}

int dp(int n)
{
	if(!n) return 0;
	vector<int> a;
	while(n) a.push_back(n%10),n/=10;
	int last=-2;
	int res=0;
	for(int i=a.size()-1;i>=0;i--)
	{
		for(int j=(i==a.size()-1);j<a[i];j++)
		{
			if(abs(j-last)>=2) res+=f[i+1][j];
		}
		if(abs(a[i]-last)<2) break;
		last=a[i];
		if(!i) res++;
	}
	for(int i=a.size()-1;i>=1;i--)
	{
		for(int j=1;j<=9;j++) res+=f[i][j];
	}
	return res;
}

int main()
{
	int a,b;
	cin>>a>>b;
	init();
	printf("%d\n",dp(max(a,b))-dp(min(a,b)-1));
	return 0;
}

3.度的数量

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define maxn 12
using namespace std;

int a[maxn],f[maxn][maxn];
int k,B;

void init()//预处理组合数
{
	for(int i=0;i<=maxn;i++) f[i][0]=1;
	for(int i=1;i<=maxn;i++)
	{
		for(int j=1;j<=i;j++)
		{
			f[i][j]=f[i-1][j-1]+f[i-1][j];
		}
	}
}

int dp(int n)
{
	if(!n) return 0;//特判,0也是一个不降数 
	int cnt=0;
	while(n) a[++cnt]=n%B,n/=B;
	int res=0,last=0;
	for(int i=cnt;i>=1;--i)
	{
		int now=a[i];
		if(now)
		{
			res+=f[i-1][k-last];
			if(now>1)
			{
				if(k-last-1>=0) res+=f[i-1][k-last-1];
				break;
			}
			else
			{
				last++;
				if(last>k) break;
			}
		}
		if(i==1&&last==k) res++;
	}
	return res;
}

int main()
{
	init();
	int l,r;
	cin>>l>>r>>k>>B;
	cout<<dp(r)-dp(l-1)<<endl;
	return 0;
}

posted on   dolires  阅读(8)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示