首页 > 其他 > 详细

POJ 2282 The Counting Problem,组合数学

时间:2014-06-07 15:38:25      阅读:386      评论:0      收藏:0      [点我收藏+]

POJ 2282 The Counting Problem,组合数学

ACM

题目地址:POJ 2282

题意

给出俩数n,m,求从n~m中0~9分别出现的次数。

分析

组合数学。 
只要能快速算出0~n中各个数的出现次数就能解决问题了。 
要把数拆开来看,比如3456=3000+400+50+6。 
然后就只要考虑后面都是0的数就行了。 
0~3000中,我们要分为两部分来考虑: 
在第一位中,0\1\2都出现了1000次。 
假设不管第一位,后面那些位数出现0~9的几率是均等的(先不考虑前导0)。那么就是0\1\2分别作为第一位,后面0~9出现的次数遍都能知道了。 
但是这样并不能直接去算后面的问题,因为第一位为3也出现了一些次数,也要算上去。 
各个位都能这样考虑。

代码

/*
*  Author:      illuz <iilluzen[at]gmail.com>
*  File:        2282.cpp
*  Create Date: 2014-06-04 09:24:27
*  Descripton:  comb 
*/

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

const int N = 10;

char s[N];
int a[N], b[N];
int n, m;

void calc(char *s, int *tab) {
	int len = strlen(s), t = 1;
	for (int i = 0; i < len - 1; i++) {
		t *= 10;
		tab[0]  -= t;	// 提前扣掉多算的0
	}
	for (int i = 0; i < len; i++) {
		int tmp = s[i] - '0';
		for (int j = 0; j < tmp; j++) {
			tab[j] += t;
		}
		for (int j = 0; j < 10; j++) {
			tab[j] += tmp * ((len - i - 1) * t / 10);
		}
		tab[tmp] += atoi(s + i + 1) + 1;
		t /= 10;
	}
}

int main() {
	while (~scanf("%d%d", &n, &m) && (n || m)) {
		memset(a, 0, sizeof(a));
		memset(b, 0, sizeof(b));
		if (n > m)
			swap(n, m);

		sprintf(s, "%d", n - 1);
		calc(s, a);
		sprintf(s, "%d", m);
		calc(s, b);
		for (int i = 0; i < N - 1; i++) {
			printf("%d ", b[i] - a[i]);
		}
		printf("%d\n", b[9] - a[9]);
	}
	return 0;
}


POJ 2282 The Counting Problem,组合数学,布布扣,bubuko.com

POJ 2282 The Counting Problem,组合数学

原文:http://blog.csdn.net/hcbbt/article/details/28395699

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!