P1020 导弹拦截

P1020 导弹拦截

提交 115.78k
通过 24.09k
时间限制 1.00s
内存限制 125.00MB
题目提供者 CCF_NOI
难度 普及/提高-
历史分数200

提交记录

查看题解

标签

NOIp普及组 Special Judge 1999
 
查看算法标签
进入讨论版

相关讨论

 
查看讨论

推荐题目

 
查看推荐
 

展开

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是≤50000 \le 5000050000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

111行,若干个整数(个数≤100000 \le 100000100000)

输出格式

222行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出样例

输入 #1
389 207 155 300 299 170 158 65
输出 #1
6
2

说明/提示

为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分

每点两问,按问给分

 

思路

   对于第一问,显然是让我们求一个最长不上升子序列。

   如何O(nlogn)来求LCS:建立一个数组来模拟单调栈,存储一个不上升序列,依次将导弹高度插进去,如果当前导弹等于或者低于栈顶的导弹高度,显然可以直接加进去;不然,如果当前导弹高于栈顶的导弹高度,就可以使用c++内置函数upperbound来在数组中寻找一个能把当前导弹塞进去的位置。

  

int p = upper_bound(d + 1, d + 1 + len, a[i], greater  () ) - d;

d[p] = a[i];

    如此一来,数组的size就是我们的答案了。

  对于第二问,是要把整个数组划分为n个不重复的不上升子序列,可以转化为求一个LIS,证明如下:

(1)假设打导弹的方法是这样的:取任意一个导弹,从这个导弹开始将能打的导弹全部打完。而这些导弹全部记为为同一组,再在没打下来的导弹中任选一个重复上述步骤,直到打完所有导弹。

 

(2)假设我们得到了最小划分的K组导弹,从第a(1<=a<=K)组导弹中任取一个导弹,必定可以从a+1组中找到一个导弹的高度比这个导弹高(因为假如找不到,那么它就是比a+1组中任意一个导更高,在打第a组时应该会把a+1组所有导弹一起打下而不是另归为第a+1组),同样从a+1组到a+2组也是如此。那么就可以从前往后在每一组导弹中找一个更高的连起来,连成一条上升子序列,其长度即为K;

 

(3)设最长上升子序列长度为P,则有K<=P;又因为最长上升子序列中任意两个不在同一组内(否则不满足单调不升),则有P>=K,所以K=P。

 

 

CODE

 1 #include 
 2 #define dbg(x) cout << #x << "=" << x << endl
 3 
 4 using namespace std;
 5 typedef long long LL;
 6 
 7 template<class T>inline void read(T &res)
 8 {
 9     char c;T flag=1;
10     while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
11     while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
12 }
13 
14 namespace _buff {
15     const size_t BUFF = 1 << 19;
16     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
17     char getc() {
18         if (ib == ie) {
19             ib = ibuf;
20             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
21         }
22         return ib == ie ? -1 : *ib++;
23     }
24 }
25 
26 int qread() {
27     using namespace _buff;
28     int ret = 0;
29     bool pos = true;
30     char c = getc();
31     for (; (c < '0' || c > '9') && c != '-'; c = getc()) {
32         assert(~c);
33     }
34     if (c == '-') {
35         pos = false;
36         c = getc();
37     }
38     for (; c >= '0' && c <= '9'; c = getc()) {
39         ret = (ret << 3) + (ret << 1) + (c ^ 48);
40     }
41     return pos ? ret : -ret;
42 }
43 
44 const int kmaxn = 1007;
45 LL f[kmaxn][kmaxn];
46 const LL mod = 1e9 + 7;
47 int n;
48 LL p[kmaxn];
49 
50 int main()
51 {
52     scanf("%d",&n);
53     for(int i = 1; i <= n; ++i) {
54         scanf("%lld",&p[i]);
55     }
56     f[0][0] = 1;
57     for(int i = 1; i <= n; ++i) {
58         f[i][0] = f[i-1][0] * (mod+1-p[i]) % mod;
59         for(int j = 1; j <= n; ++j) {
60             f[i][j] = ((f[i-1][j]*(i-p[i]+mod)) % mod + f[i-1][j-1]*(mod+p[i]) % mod)% mod;
61         }
62     }
63     for(int i = 0; i < n; ++i) {
64         printf("%lld ",f[n][i]);
65     }
66     printf("%lld\n",f[n][n]);
67     return 0;
68 }
View Code

 

你可能感兴趣的:(P1020 导弹拦截)