D - Bomb HDU - 3555
The counter-terrorists found a time bomb in the dust.
But this time the terrorists improve on the time bomb.
The number sequence of the time bomb counts from 1 to N.
If the current number sequence includes the sub-sequence "49", the power of the blast would add one point.
Now the counter-terrorist knows the number N.
They want to know the final points of the power. Can you help them?
InputThe first line of input consists of an integer T (1 <= T <= 10000), indicating the number of test cases. For each test case, there will be an integer N (1 <= N <= 2^63-1) as the description.
The input terminates by end of file marker.
OutputFor each test case, output an integer indicating the final points of the power.
Sample Input
3 1 50 500
Sample Output
0 1 15
题意: 要求一段区间内含49的数的个数.
分析: 考虑一下搜索,我们有dfs(int deep, bool flag, bool Y, bool lmt)
deep表示当前数的位数,flag表示上一个数位是不是为4, Y表示数字含有49
所以我们有,当flag==4的时候,下一个数位是9的时候Y应该为true,并且会影响之后的搜索.
同时我们的记忆数组也可以定义出来了: dp[deep][flag][Y]
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[64]; ll dp[64][2][2]; ll dfs(int deep, bool Y, bool flag, bool lmt) { if (!deep) return Y; if (!lmt && dp[deep][Y][flag]>=0) return dp[deep][Y][flag]; int i, up = lmt ? digit[deep] : 9; ll res = 0; for (i=0; i<=up; ++i) res += dfs(deep-1, Y || (flag && i==9), i==4, lmt && i==up); return lmt ? res : dp[deep][Y][flag] = res; } ll cal(ll n) { int k = 1; while (n) { digit[k++] = n % 10; n /= 10; } return dfs(k-1, false, false, true); } int main() { int t; ll v; scanf("%d", &t); memset(dp, -1, sizeof dp); while (t--) { scanf("%I64d", &v); printf("%I64d ", cal(v)); } }
C - 不要62 HDU - 2089
杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,
不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,
更安全地服务大众。
不吉利的数字为所有含有4或62的号码。例如:
62315 73418 88914
都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input
1 100 0 0
Sample Output
80
题意: 要求一段区间不含4和62的数的个数.
分析: 考虑一下搜索,我们有dfs(int deep, bool flag, bool lmt)
deep表示当前数的位数,flag表示上一个数位是不是为6,如果是下一个数是2就不进行搜索
如果数位是4也不进行搜索
同时我们的记忆数组也可以定义出来了: dp[deep][flag]
#include <cstdio> #include <cstring> using namespace std; int digit[10]; int dp[11][2]; inline int dfs(int deep, bool flag, bool lmt) { if (!deep) return 1; if (!lmt && dp[deep][flag]>=0) return dp[deep][flag]; int up = lmt ? digit[deep] : 9; int i, cnt = 0; for (i=0; i<=up; ++i) { if (i==4) continue; if (flag && i==2) continue; cnt += dfs(deep-1, i==6, lmt && i==up); } return lmt ? cnt : dp[deep][flag]=cnt; } int cal(int num) { int i, k = 1; while (num) { digit[k++] = num % 10; num /= 10; } return dfs(k-1, false, true); } int main() { int a, b; memset(dp, -1, sizeof(dp)); while (scanf("%d%d", &a, &b) && (a || b)) printf("%d ", cal(b)-cal(a-1)); return 0; }
E - Round Numbers POJ - 3252
The cows, as you know, have no fingers or thumbs and thus are unable to play Scissors,
Paper, Stone' (also known as 'Rock, Paper, Scissors', 'Ro, Sham, Bo', and a host of other names)
in order to make arbitrary decisions such as who gets to be milked first.
They can't even flip a coin because it's so hard to toss using hooves.
They have thus resorted to "round number" matching. The first cow picks an integer less than two billion. The second cow does the same.
If the numbers are both "round numbers", the first cow wins,
otherwise the second cow wins.
A positive integer N is said to be a "round number" if the binary representation of N has as many or more zeroes than it has ones.
For example, the integer 9, when written in binary form, is 1001. 1001 has two zeroes and two ones;
thus, 9 is a round number. The integer 26 is 11010 in binary; since it has two zeroes and three ones, it is not a round number.
Obviously, it takes cows a while to convert numbers to binary, so the winner takes a while to determine.
Bessie wants to cheat and thinks she can do that if she knows how many "round numbers" are in a given range.
Help her by writing a program that tells how many round numbers appear in the inclusive range given by the input (1 ≤ Start < Finish ≤ 2,000,000,000).
Input
Output
Sample Input
2 12
Sample Output
6
题意:要我们找一段区间内,数字的二进制表示,零的个数大于等于一的个数的数字有多少个.
分析:范围只有2e9所以,我们不妨直接把数字转换成二进制,直接进行数位dp.
因为要比较0和1的个数,所以我们可以写出我们的dfs函数: dfs(int deep, int zero, int one, bool flag)
zero表示零的个数, one表示一的个数.
记录数组为: dp[deep][zero][one], 然后我们发现zero one最多只有64个,所以是可行的.
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[64]; ll dp[64][64][64]; ll dfs(int deep, int zero, int one, bool lmt) { // printf("%d %d ", zero, one); if (!deep) return zero >= one; if (!lmt && dp[deep][zero][one]>=0) return dp[deep][zero][one]; int i, up = lmt ? digit[deep] : 1; ll res = 0; for (i=0; i<=up; ++i) res += dfs(deep-1, one ? zero + (i==0) : 0, one + (i==1), lmt && i==up); return lmt ? res : dp[deep][zero][one] = res; } ll cal(ll n) { int k = 1; while (n) { digit[k++] = n % 2; n /= 2; } return dfs(k-1, 0, 0, true); } int main() { ll left, right; memset(dp, -1, sizeof dp); scanf("%I64d%I64d", &left, &right); printf("%I64d", cal(right) - cal(left-1)); }
G - B-number HDU - 3652
InputProcess till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).
OutputPrint each answer in a single line.
Sample Input
13 100 200 1000
Sample Output
1 1 2 2
题意: 要我们找1~n之间可以被13整除和包含13的整数.
分析: 还是简单的一道题,我们这样定义我们的dfs函数:
dfs(int deep, int state, bool one, bool Y, bool lmt)
one表示上一个数位为1, Y 表示这个数字包含13,state表示这个数对13取模,如果最后为0说明可以被13整除.
同时,我们的记录数组为: dp[deep][state][one][Y]
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[64]; ll dp[64][13][2][2]; ll dfs(int deep, int state, bool one, bool flag, bool lmt) { // printf("%d %d ", zero, one); if (!deep) return state%13==0 && flag; if (!lmt && dp[deep][state][one][flag]>=0) return dp[deep][state][one][flag]; int i, up = lmt ? digit[deep] : 9; ll res = 0; for (i=0; i<=up; ++i) res += dfs(deep-1, (state*10+i)%13, i==1, flag || (one && i==3), lmt && i==up); return lmt ? res : dp[deep][state][one][flag] = res; } ll cal(ll n) { int k = 1; while (n) { digit[k++] = n % 10; n /= 10; } return dfs(k-1, 0, 0, 0, true); } int main() { ll n; memset(dp, -1, sizeof dp); while (~scanf("%I64d", &n)) { printf("%I64d ", cal(n)); } }
A - Beautiful numbers CodeForces - 55D
Volodya is an odd boy and his taste is strange as well.
It seems to him that a positive integer number is beautiful if and only if it is divisible by each of its nonzero digits.
We will not argue with this and just count the quantity of beautiful numbers in given ranges.
Input
The first line of the input contains the number of cases t (1 ≤ t ≤ 10). Each of the next t lines contains two natural numbers li and ri (1 ≤ li ≤ ri ≤ 9 ·1018).
Please, do not use %lld specificator to read or write 64-bit integers in C++. It is preffered to use cin (also you may use %I64d).
Output
Output should contain t numbers — answers to the queries, one number per line — quantities of beautiful numbers in given intervals (from li to ri, inclusively).
1
1 9
9
1
12 15
2
题意:
如果一个数可以被它每一个数位整除的话,那么这个数就称为一个美数.
现在要我们求区间有多个美数.
分析: 当一个数是美数时,那么他一定可以被它的所有数位的最小公倍数整除.
所以我们可以初步定义dfs(int deep, int val, int lcm, bool lmt)
其中val是这个数,lcm是它所有数位的最小公倍数.
同时,我们需要一个数组来记录我们搜索过程中的状态:
dp[deep][val][lcm] val和lcm的定义就是dfs中的val和lcm.
然后我们发现,如果val和lcm太大了,我们是开不下的. 所以我们需要减小val和lcm.
我们发现,对于一个大于2520(1,2,3,4,5,6,7,8,9的最小公倍数)的数,
我们可以直接在计算的过程中对2520取模,所以val的范围是[0,2520)
但lcm的范围也是[0,2520),所以我们还需要缩小val或者lcm.
我们发现1,2,3,4,5,6,7,8,9的最小公倍数最多只有48个,所以我们类似hash弄一下,
所以lcm这一维就只有48了.
所以我们的数组开: dp[20][2520][48]就行了.
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[20]; ll dp[20][2520][48]; int _h[2521]; inline int gcd(int a, int b) { return b ? gcd(b, a%b) : a; } inline int lcm(int a, int b) { return a / gcd(a, b) * b; } ll dfs(int deep, int val, int lc, bool lmt) { if (!deep) return val % lc == 0; if (!lmt && dp[deep][val][_h[lc]] >= 0) return dp[deep][val][_h[lc]]; int i, tmp; ll cnt = 0; int up = lmt ? digit[deep] : 9; for (i=0; i <= up; ++i) { if (i) tmp = lcm(lc, i); else tmp = lc; cnt += dfs(deep-1, (val * 10 + i) % 2520, tmp, lmt && i==up); } return lmt ? cnt : dp[deep][val][_h[lc]] = cnt; } ll cal(ll n) { int k = 1; while (n) { digit[k++] = n % 10; n /= 10; } return dfs(k-1, 0, 1, true); } int main() { int t; int i, j; j = 0; for (i=1; i<=2520; ++i) if (2520 % i == 0) _h[i] = j++; memset(dp, -1, sizeof(dp)); scanf("%d", &t); ll left, right; while (t--) { scanf("%I64d%I64d", &left, &right); printf("%I64d ", cal(right) - cal(left-1)); } return 0; }
F - Balanced Number HDU - 3709
to calculate the number of balanced numbers in a given range [x, y].
InputThe input contains multiple test cases.
The first line is the total number of cases T (0 < T ≤ 30).
For each case, there are two integers separated by a space in a line, x and y. (0 ≤ x ≤ y ≤ 10 18).
OutputFor each case, print the number of balanced numbers in the range [x, y] in a line.
Sample Input
2 0 9 7604 24324
Sample Output
10 897
题意: 例如有一个数,这个数由ABCDEFGH组成, 我们可以任取一位做为他的重心,
例如我们取C作为重心,那么这个数的左边值就为: A*2 + B*1 右边值为: D*1 + E*2 + F*3
然后问一段区间内左值和右值相等的数的个数.
分析: 我们不妨假设,所有数的重心都是一样的(虽然这显然是不对的,但是不妨我们先这样考虑),
那么我们就可以这样数位dp, 我们定义我们的dfs函数:
dfs(int deep, int heart, int left, int right, bool flag)
heart表示的是重心位置, left是左值,right是右值.
如果所有数的重心都是一样的,那么答案就算出了,但是事实不是这样.
所有我们不妨把每一个位置都当成重心进行枚举.如果对于每一个数,它的重心是唯一的,
那么枚举答案的累加就是我们的最终答案,所以,我们现在的问题是:
数的重心是不是唯一的呢?
我们假设 有一个数字: ABCDEFG, D为重心时,左值等于右值.
所以有A*3 + B*2 + C = E + F*2 + G*3
如果这个数除D以外,又有一个重心C, 那么就有
A*2 + B = D*1 + E*2 + F*3 + G*4 = A*3 + B*2 + C + D + E + F +G,
这显然是不成立的.
大概就是这样证明,所以数的重心只有一个.
所以我们枚举重心就行了.
所以根据dfs(int deep, int heart, int left, int right, bool flag)
我们定义出我们的记忆数字dp[deep][heart][left][right],然后我们发现,极端情况下,left和right都可以达到几千.
内存是开不下的. 所以我们需要优化.
很显然,我们可以这样定义dfs(int deep, int heart, int deta, bool zf, bool flag)
deta表示left-right zf表示的deta的符号,所以我们的记忆数组就变为:
dp[deep][heart][deta][zf] 可以开得下.
然后有个小坑点需要注意下: 0也是答案, 所以我们每次枚举重心位置的时候,都会把0重复统计一遍.
#include <cmath> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[24]; ll dp[24][24][4000][2]; ll dfs(int deep, int mid, int deta, bool flag, bool lmt) { if (!deep) { return deta == 0; } if (!lmt && dp[deep][mid][abs(deta)][flag]>=0) return dp[deep][mid][abs(deta)][flag]; int i, up = lmt ? digit[deep] : 9; ll res = 0; int tmp = 0; bool tflag; for (i=0; i<=up; ++i) { if (deep > mid) tmp = deta + (deep-mid)*i; else if (deep < mid) tmp = deta - (mid-deep)*i; else tmp = deta; if (tmp >= 0) tflag = true; else tflag = false; res += dfs(deep-1, mid, tmp, tflag, i==up && lmt); } return lmt ? res : dp[deep][mid][abs(deta)][flag] = res; } ll cal(ll n) { int i, k = 0; while (n) { digit[++k] = n % 10; n /= 10; } ll res = 0; for (i=k; i>=1; --i) res += dfs(k, i, 0, true, true); return res - k + 1; } int main() { // freopen("E:\input.txt", "r", stdin); int t; t = 0; memset(dp, -1, sizeof(dp)); scanf("%d", &t); ll left, right; while (t--) { scanf("%I64d%I64d", &left, &right); printf("%I64d ", cal(right) - cal(left-1)); } return 0; }
其实,我们还可以发现,如果deta<0的时候,我们就不需要再继续下去了,因为后面deta都是小于0的了.
所以我们可以去掉zf这个变量.
#include <cmath> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[24]; ll dp[24][24][4000]; ll dfs(int deep, int mid, int deta, bool lmt) { if (!deep) return deta == 0; if (deta < 0) return 0; if (!lmt && dp[deep][mid][deta]>=0) return dp[deep][mid][deta]; int i, up = lmt ? digit[deep] : 9; ll res = 0; for (i=0; i<=up; ++i) res += dfs(deep-1, mid, deta+(deep-mid)*i, i==up && lmt); return lmt ? res : dp[deep][mid][deta] = res; } ll cal(ll n) { int i, k = 0; while (n) { digit[++k] = n % 10; n /= 10; } ll res = 0; for (i=k; i>=1; --i) res += dfs(k, i, 0, true); return res - k + 1; } int main() { //freopen("E:\input.txt", "r", stdin); int t; t = 0; memset(dp, -1, sizeof(dp)); scanf("%d", &t); ll left, right; while (t--) { scanf("%I64d%I64d", &left, &right); printf("%I64d ", cal(right) - cal(left-1)); } return 0; }
H - F(x) HDU - 4734
InputThe first line has a number T (T <= 10000) , indicating the number of test cases.
For each test case, there are two numbers A and B (0 <= A,B < 10 9)OutputFor every case,
you should output "Case #t: " at first,
without quotes. The t is the case number starting from 1. Then output the answer.
Sample Input
3 0 100 1 10 5 100
Sample Output
Case #1: 1 Case #2: 2 Case #3: 13
题意: x有n位数,由AnAn-1...A1组成 F(x)=An*2^(n-1) + A(n-1)*2^(n-2)+ ... + A1*1;
然后给出A,B两个数,问区间0到B有多少个数的 F()小于F(A)
分析: 我们已经知道了F(A), 然后接下来我们要判断[0,B]中小于等于F(A)的数的个数.
我们不妨把F(A)作为我们dfs函数的参数,即dfs(int deep, int state, bool lmt)
state表示的是F(A)减去现在数的大小后的剩余量,很显然,如果state<0,那么就是对答案没有贡献,
如果到了最后state>=0那么就对答案有贡献.
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; int digit[10]; int dp[10][4600]; int pwr[] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536}; int get(int val) { int k = 0; while (val) { digit[++k] = val % 10; val /= 10; } int res = 0; while (k--) res += pwr[k] * digit[k+1]; return res; } int dfs(int deep, int state, bool lmt) { if (state < 0) return 0; if (!deep) return 1; if (!lmt && dp[deep][state]>=0) return dp[deep][state]; int i, up = lmt ? digit[deep] : 9; int res = 0; for (i=0; i<=up; ++i) res += dfs(deep-1, state-pwr[deep-1]*i, i==up && lmt); return lmt ? res : dp[deep][state] = res; } int cal(int lmt, int val) { int k = 0; while (val) { digit[++k] = val % 10; val /= 10; } return dfs(k, lmt, true); } int main() { // freopen("E:\input.txt", "r", stdin); int t; memset(dp, -1, sizeof(dp)); scanf("%d", &t); int left, right; for (int cas=1; cas<=t; ++cas) { scanf("%d%d", &left, &right); printf("Case #%d: %d ", cas, cal(get(left), right)); } return 0; }
K - Balanced Number SPOJ - BALNUM
Balanced numbers have been used by mathematicians for centuries. A positive integer is considered a balanced number if:
1) Every even digit appears an odd number of times in its decimal representation
2) Every odd digit appears an even number of times in its decimal representation
For example, 77, 211, 6222 and 112334445555677 are balanced numbers while 351, 21, and 662 are not.
Given an interval [A, B], your task is to find the amount of balanced numbers in [A, B] where both A and B are included.
Input
The first line contains an integer T representing the number of test cases.
A test case consists of two numbers A and B separated by a single space representing the interval. You may assume that 1 <= A <= B <= 1019
Output
For each test case, you need to write a number in a single line: the amount of balanced numbers in the corresponding interval
Example
Input: 2 1 1000 1 9
Output: 147 4
题意: 问区间内满足条件的数的个数.
需要满足的条件: 如果一个数的某个数位上的数字是奇数,那么这个数字应该出现偶数次
如果一个数的某个数位上的数字是偶数,那么这个数字应该出现奇数次.
如果我们傻傻的定义我们的dfs函数,那么我们可以定义出
dfs(int deep, int zero, int one, int two, ... int nine, bool lmt)
其中zero,one,two表示这个数字出现的次数. 同时dp数组也会开到11维...很明显是不行的,
但是这个解题思路是可行的.所以我们考虑下如何压缩这些状态.
对于一个数,有三种状态: 没出现过, 出现奇数次, 出现偶数次.
所以我们考虑一下.用三进制来表示0~9这几个数字出现的状态.
然后我们计算一下2*(3^9+3^8+..+3)大概就是60000左右的样子.可以存.
所以我们的dfs函数就变成了: dfs(int deep, int state, bool lmt)
记忆数组也变成了 dp[deep][state]
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; ll digit[32]; ll dp[32][60000]; inline ll tentothree(ll v) { ll res = 0, t = 1; while (v) { res = res + v % 3 * t; t *= 10; // printf() v /= 3; } return res; } inline bool isok(ll v) { ll t; v = tentothree(v); for (ll i=0; i<=9; ++i) { t = v % 10; v /= 10; if (i%2==1 && t==1) return false; if (i%2==0 && t==2) return false; } return true; } inline ll update(ll v, ll id) { ll i, j, t = 1; for (i=1; i<=id; ++i) t *= 3; ll tt, tmp = v; // return v + t; tmp = tentothree(tmp); do { tt = tmp % 10; tmp /= 10; } while (id--); if (tt <= 1) { v += t; } else { v -= t; } return v; } ll dfs(ll deep, ll state, bool lmt) { // printf("%d %d ", deep, state); if (!deep) return isok(state); if (!lmt && dp[deep][state]>=0) return dp[deep][state]; ll i, up; up = lmt ? digit[deep] : 9; ll cnt = 0; for (i=0; i<=up; ++i) cnt += dfs(deep-1, (state || i) ? update(state, i) : 0, lmt && i==up); return lmt ? cnt : dp[deep][state] = cnt; } ll cal(ll n) { ll k = 1; while (n) { digit[k++] = n % 10; n /= 10; } return dfs(k-1, 0, true); } int main() { // printf("%I64d ", tentothree(56000)); // freopen("E:\input.txt", "r", stdin); ll t; ll left, right; scanf("%lld", &t); memset(dp, -1, sizeof(dp)); while (t--) { scanf("%lld%lld", &left, &right); printf("%lld ", cal(right) - cal(left-1)); } return 0; }
J - 吉哥系列故事――恨7不成妻 HDU - 4507
依然单身!
吉哥依然单身!
DS级码农吉哥依然单身!
所以,他生平最恨情人节,不管是214还是77,他都讨厌!
吉哥观察了214和77这两个数,发现:
2+1+4=7
7+7=7*2
77=7*11
最终,他发现原来这一切归根到底都是因为和7有关!所以,他现在甚至讨厌一切和7有关的数!
什么样的数和7有关呢?
如果一个整数符合下面3个条件之一,那么我们就说这个整数和7有关——
1、整数中某一位是7;
2、整数的每一位加起来的和是7的整数倍;
3、这个整数是7的整数倍;
现在问题来了:吉哥想知道在一定区间内和7无关的数字的平方和。
Input输入数据的第一行是case数T(1 <= T <= 50),然后接下来的T行表示T个case;每个case在一行内包含两个正整数L, R(1 <= L <= R <= 10^18)。
Output请计算[L,R]中和7无关的数字的平方和,并将结果对10^9 + 7 求模后输出。Sample Input
3 1 9 10 11 17 17
Sample Output
236 221 0
题意: Find .....
分析: 先贴代码..写了一早上 不想写了...
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; struct nobe { ll cnt, sum, qsum; nobe () { } nobe (ll cc, ll ss, ll qq) : cnt(cc), sum(ss), qsum(qq) { } }; const ll mod = 1e9+7; ll digit[28]; nobe dp[28][7][7]; ll pwr[28]; nobe dfs(int deep, int st1, int st2, bool lmt) { if (!deep) return nobe(((st1) && (st2))*1ll, 0ll, 0ll); if (!lmt && dp[deep][st1][st2].qsum>=0) return dp[deep][st1][st2]; int i, up = lmt ? digit[deep] : 9; nobe now(0ll, 0ll, 0ll), lst; for (i=0; i<=up; ++i) { if (i == 7) continue; lst = dfs(deep-1, (st1+i)%7, (st2*10+i)%7, i==up && lmt); now.cnt = (now.cnt + lst.cnt) % mod; now.sum = ((now.sum + lst.sum) % mod + lst.cnt * pwr[deep-1] % mod * i % mod) % mod; now.qsum = ((now.qsum + lst.qsum) % mod + 2 * lst.sum % mod * i * pwr[deep-1] % mod + lst.cnt * i % mod * i % mod * pwr[deep-1] % mod * pwr[deep-1] % mod) % mod; } return lmt ? now : dp[deep][st1][st2] = now; } ll cal(ll n) { int k = 0; while (n) { digit[++k] = n % 10; n /= 10; } return dfs(k, 0, 0, true).qsum; } int main() { // freopen("E:\input.txt", "r", stdin); int t, i; scanf("%d", &t); ll left, right; memset(dp, -1, sizeof(dp)); pwr[0] = 1; for (i=1; i<28; ++i) pwr[i] = pwr[i-1] * 10 % mod; while (t--) { scanf("%I64d%I64d", &left, &right); printf("%I64d ", ((cal(right) - cal(left-1)) % mod + mod) % mod); } return 0; }
B - XHXJ's LIS HDU - 4352
If you do not know xhxj, then carefully reading the entire description is very important.
As the strongest fighting force in UESTC, xhxj grew up in Jintang, a border town of Chengdu.
Like many god cattles, xhxj has a legendary life:
2010.04, had not yet begun to learn the algorithm,
As you see, xhxj always keeps a short hair(reasons unknown),
Xhxj loves many games such as,Dota, ocg, mahjong, Starcraft 2, Diablo 3.etc,
For the first one to solve this problem,xhxj will upgrade 20 favorability rate。
InputFirst a integer T(T<=10000),then T lines follow,
every line has three positive integer L,R,K.( 0<L<=R<2 63-1 and 1<=K<=10).
OutputFor each query, print "Case #t: ans" in a line,
in which t is the number of the test case starting from 1 and ans is the answer.
Sample Input
1 123 321 2
Sample Output
Case #1: 139
题意: 以数的数字为一个序列,问严格上升的子序列的最长长度为k的数的个数.
分析:
#include <cstdio> #include <cstring> using namespace std; typedef long long ll; ll dp[72][1228][16]; int digit[72]; int K; inline int GetLen(int v) { int i, cnt = 0; for (i=0; i<=9; ++i) if (v & (1 << i)) cnt++; return cnt; } inline int Update(int v, int nt) { for (int i=nt; i<=9; ++i) { if (v & (1 << i)) { v = v ^ (1 << i); break; } } return v | (1 << nt); } ll dfs(int deep, int state, bool lmt) { if (!deep) return GetLen(state) == K; if (!lmt && dp[deep][state][K]>=0) return dp[deep][state][K]; int i, up = lmt ? digit[deep] : 9; ll cnt = 0; for (i=0; i<=up; ++i) cnt += dfs(deep-1, (state==0 && i==0) ? 0 : Update(state, i), lmt && i==up); return lmt ? cnt : dp[deep][state][K] = cnt; } ll cal(ll n) { int t = 1; while (n) { digit[t++] = n % 10; n /= 10; } return dfs(t-1, 0, true); } int main() { // freopen("E:\input.txt", "r", stdin); int t; scanf("%d", &t); ll left, right; memset(dp, -1, sizeof dp); for (int cas=1; cas<=t; ++cas) { scanf("%I64d%I64d%d", &left, &right, &K); printf("Case #%d: %I64d ", cas, cal(right) - cal(left-1)); } return 0; }