AW311 月之谜

题目地址


状态设计:

  • f[当前位数][之前每一位的和][当前余数][当前位数字是否与原数相同].
  • 转移方式是通过余数的结构持久保存和对初始状态的特殊判定实现的.
  • 在代码中之所以需要分开进行转移,是由于需要在保证当前数字在范围内的同时又需要对一些高位小但其他位大的数字进行转移。为了兼顾两种情况,将初始状态设为需要判定才能转移即可.

易错点:

  • 需要对取模运算的深刻认识.
  • 需要对数位DP转移方式的深刻认识.

一句话总结:

  • 完美的线性递推结构与合理的状态设计思想.

#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
ll f[25][190][190][2],dight[25],dightTop=0;
ll calc(ll num,int mod){
	memset(f,0,sizeof(f));
	dightTop=0;
	while(num){
		dight[++dightTop]=num%10;
		num/=10;
	}
	f[dightTop+1][0][0][1]=1;
	for(int i=dightTop+1;i>1;i--){
		for(int j=0;j<=mod;j++){
			for(int k=0;k<mod;k++){
				if(!f[i][j][k][0]&&!f[i][j][k][1])continue;
				for(int p=0;p<=9;p++){
					f[i-1][j+p][(k*10+p)%mod][0]+=f[i][j][k][0];
					if(p==dight[i-1])f[i-1][j+p][(k*10+p)%mod][1]+=f[i][j][k][1];
					else if(p<dight[i-1])f[i-1][j+p][(k*10+p)%mod][0]+=f[i][j][k][1];		
				}
			}
		}
	}
	return f[1][mod][0][0]+f[1][mod][0][1];
}
int main(){
	ll l,r;
	scanf("%lld%lld",&l,&r);
	ll ans=0,dightNumber=9*21;
	for(int i=1;i<dightNumber;i++){
		ans+=calc(r,i)-calc(l-1,i);
	}
	printf("%lld\n",ans);
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值