51nod1009 – 数字1的数量(数位DP)

51nod1009

【分析】以前数位DP只会用模版,一直没有仔细考虑过,最近又碰到一些决定仔细理解下,这题是自己想出来的,虽然题目很简单,还是蛮有成就感的。

预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为:

if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);
else dp[i][j] = dp[i-1][9]+dp[i][j-1];

然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1);

这样总复杂度log(n)*10

【AC CODE】15ms

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,n) for(int i = a; i < n; i++)
#define repe(i,a,n) for(int i = a; i <= n; i++)
#define per(i,n,a) for(int i = n; i >= a; i--)
#define clc(a,b) memset(a,b,sizeof(a))
const int INF = 0x3f3f3f3f, MAXN = 11;
int dp[MAXN][10];//dp[i][j]从1~以j开头的i位数中有几个1
int bit[MAXN];

int main()
{
#ifdef SHY
	freopen("d:\\1.txt", "r", stdin);
#endif
	int tmp = 10;
	rep(i,1,10) dp[1][i] = 1;
	repe(i,2,9)
	{
		rep(j,1,10)
		{
			if(j == 1) dp[i][j] = dp[i-1][9]+tmp;
			else dp[i][j] = dp[i][j-1];
			dp[i][j] += dp[i-1][9];
		}
		tmp *= 10;
	}
	int n,cnt = 0;
	scanf("%d", &n);
	tmp = n;
	while(tmp)
	{
		bit[++cnt] = tmp%10;
		tmp /= 10;
	}
	int ans = 0,sum = 0;
	per(i,cnt,1)
	{
		if(bit[i] == 0) continue;
		if(bit[i] == 1)
			ans += dp[i-1][9]+1+n%((int)pow(10,i-1));
		else
			ans += dp[i][bit[i]-1];
	}
	printf("%d\n", ans);
	return 0;
}

 

发表评论

邮箱地址不会被公开。 必填项已用*标注

请输入正确的验证码