POJ 2282 The Counting Problem,组合数学

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,组合数学

时间: 2024-12-09 10:23:11

POJ 2282 The Counting Problem,组合数学的相关文章

[POJ 2282] The Counting Problem

[题目链接] http://poj.org/problem?id=2282 [算法] 数位DP [代码] #include <algorithm> #include <bitset> #include <cctype> #include <cerrno> #include <clocale> #include <cmath> #include <complex> #include <cstdio> #inclu

POJ 2282-The Counting Problem(组合数学_区间计数)

The Counting Problem Time Limit:3000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 2282 Appoint description:  System Crawler  (2015-04-15) Description Given two integers a and b, we write the numbers between

UVALive3261 UVA1640 POJ2282 HDU1663 ZOJ2392 The Counting Problem

Regionals 2004 >> Asia - Shanghai 问题链接:UVALive3261 UVA1640 POJ2282 HDU1663 ZOJ2392 The Counting Problem. 问题简述:输入m和n,计算m到n(包括m和n)之间各个数中包含多少个0-9数字. 问题分析:先分别计算0到m-1和0到n之间数的数字个数,结果=0到n之间数的数字个数-0到m-1之间数的数字个数.计算0到n之间数的数字个数时,先考虑1位数.2位数.......,在小于n的区间逐步统计.

POJ 2800 Joseph&#39;s Problem

给n 和 k 求: ∑1<=i<=n(k mod i). p  = k/i k mod i = k - p * i k mod ( i + 1 ) = k - p * ( i + 1 ) = k mod i - p k mod ( i + 2 ) = k - p * ( i + 2 ) = k mod i - 2 * p 对于连续的 i ,很多p都是一样的 . 相差的部分是一个等差数列 , i 的 范围是 从 i 到 min(k/p,n) 如果 p == 0 则 一直延续到最后 Joseph'

POJ 3286- How many 0&#39;s?(组合数学_区间计数)

How many 0's? Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Practice POJ 3286 Appoint description:  System Crawler  (2015-04-18) Description A Benedict monk No.16 writes down the decimal representations of

POJ 2386 Lake Counting 搜索题解

简单的深度搜索就可以了,看见有人说什么使用并查集,那简直是大算法小用了. 因为可以深搜而不用回溯,故此效率就是O(N*M)了. 技巧就是增加一个标志P,每次搜索到池塘,即有W字母,那么就认为搜索到一个池塘了,P值为真. 搜索过的池塘不要重复搜索,故此,每次走过的池塘都改成其他字母,如'@',或者'#',随便一个都可以. 然后8个方向搜索. #include <stdio.h> #include <vector> #include <string.h> #include

POJ 3468 A Simple Problem with Integers(线段树)

题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 56005   Accepted: 16903 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with

poj 3468 A Simple Problem with Integers 【线段树-成段更新】

题目:poj 3468 A Simple Problem with Integers 题意:给出n个数,两种操作 1:l -- r 上的所有值加一个值val 2:求l---r 区间上的和 分析:线段树成段更新,成段求和 树中的每个点设两个变量sum 和 num ,分别保存区间 l--r 的和 和l---r 每个值要加的值 对于更新操作:对于要更新到的区间上面的区间,直接进行操作 加上 (r - l +1)* val .下面的区间标记num += val 对于求和操作,每次进行延迟更新,把num值

POJ 3468 A Simple Problem with Integers(线段树区间更新)

题目地址:POJ 3468 打了个篮球回来果然神经有点冲动..无脑的狂交了8次WA..居然是更新的时候把r-l写成了l-r... 这题就是区间更新裸题.区间更新就是加一个lazy标记,延迟标记,只有向下查询的时候才将lazy标记向下更新.其他的均按线段树的来就行. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <math.h> #include <stac