数字游戏 数位DP

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数字游戏 数位DP相关的知识,希望对你有一定的参考价值。

题目:

由于科协里最近真的很流行数字游戏,某人又命名了一种取模数,这种数字必须满足各位数字之和 m o d   N mod\\ N mod N 0 0 0。现在大家又要玩游戏了,指定一个整数闭区间 [ a , b ] [a,b] [a,b],问这个区间内有多少个取模数。

思路:

  • 状态表示:
    f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]代表共i位,最高位为j,且每个位的数之和模N余数为k的数的个数
  • 状态转移:
    f [ i ] [ j ] [ k ] = ∑ x = 0 9 f [ i − 1 ] [ x ] [ m o d ( k − j , p ) ] f[i][j][k] = \\sum _{x=0}^{9}f[i-1][x][mod(k-j,p)] f[i][j][k]=x=09f[i1][x][mod(kj,p)],因为少了一位,所以最高位是随便的
    last记录之前访问的位上数的和

代码:

#include<bits/stdc++.h>
using namespace std;
const int N = 35;
int p;
int f[N][10][105];

int mod(int a,int b)
{
	return (a%b+b)%b;
}
void init()
{
	memset(f,0,sizeof f);
	for(int i=0;i<=9;i++) f[1][i][i%p]=1;
	
	for(int i=2;i<N;i++)
		for(int j=0;j<=9;j++)
			for(int k=0;k<p;k++)
				for(int x=0;x<=9;x++)
					f[i][j][k] += f[i-1][x][mod(k-j,p)];
}

int dp(int n)
{
	if(!n) return 1;
	
	vector<int>nums;
	while(n) nums.push_back(n%10),n/=10;
	
	int last = 0;
	int res = 0;
	for(int i=nums.size()-1;i>=0;i--)
	{
		int x = nums[i];
		
		for(int j=0;j<x;j++)
			res += f[i+1][j][mod(-last,p)];
		last += x;
		if(!i && last%p==0) res ++;//访问到最后一位时,且满足所有位的数的和模p余0,加上本身这个数
	}
	return res ; 
}
int main()
{
	
	int l,r;
	while(cin>>l>>r>>p)
	{
		init();
		cout<<dp(r)-dp(l-1)<<'\\n';
	}
		
	return 0;
}

以上是关于数字游戏 数位DP的主要内容,如果未能解决你的问题,请参考以下文章

Acwing 1084. 数字游戏 II

BZOJ1833: [ZJOI2010]count 数字计数 (数位dp)

51Nod 1042 数字0-9的数量(数位DP)

数位DP::SoSDP

数位dp

数位dp——奏响数字数位的美妙乐章