一、题目:
Description
给定两个正整数 a 和 b,求在 [a,b] 中的所有整数中,每个数码(digit)各出现了多少次。
Input
仅包含一行两个整数 a,b,含义如上所述。
Output
包含一行十个整数,分别表示 0∼90∼9 在 [a,b] 中出现了多少次。
Sample 1
Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度,计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
Input
一行,若干个整数,中间由空格隔开。
Output
两行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
Sample 1
Inputcopy Outputcopy 389 207 155 300 299 170 158 65 6 2Hint
对于前 50%50% 数据(NOIP 原题数据),满足导弹的个数不超过 104104 个。该部分数据总分共 100100 分。可使用O(n2) 做法通过。
对于后 50%50% 的数据,满足导弹的个数不超过 105105 个。该部分数据总分也为 100100 分。请使用 O(nlogn) 做法通过。对于全部数据,满足导弹的高度为正整数,且不超过 5×1045×104。
此外本题开启 spj,每点两问,按问给分。
upd 2022.8.24upd 2022.8.24:新增加一组 Hack 数据。
Hint
数据规模与约定
二、思路:
Dilworth 定理
可看作把序列分成不上升子序列的最少个数,等于序列的最长上升子序列长度。把序列分成不降子序列的最少个数,等于序列的最长下降子序列长度,则第二问等价于最长上升子序列。
三、代码:
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010;
int b[N];
int a[N], f[N];
int res, c = 0, num = 0;
int main() {
while (scanf("%d", &b[++res]) != EOF) {
if (c == 0 || b[res] <= a[c]) a[++c] = b[res];
else {
int l = 1, r = c;
while (l < r) {
int mid = (l + r) >> 1;
if (a[mid] < b[res]) r = mid;
else l = mid + 1;
}
a[l] = b[res];
}
}
cout << c << endl;
num++, f[1] = b[1];
for (int i = 2; i <= res; i++) {
if (f[num] < b[i]) {
f[++num] = b[i];
continue;
}
int l = 1, r = num;
while (l < r) {
int mid = (l + r) >> 1;
if (f[mid] >= b[i]) r = mid;
else l = mid + 1;
}
f[l] = b[i];
}
cout << num << endl;
return 0;
}