NOIP基本算法

NOIP基本算法

1、二分

poj 2018 Best Cow Fences

http://poj.org/problem?id=2018

▪ 题意:给定一个正整数数列𝐴,求一个平均数最大的长度不小于𝐿 的子段。
▪ 二分答案(平均值)

▪ 判定是否存在一个长度不小于𝐿 的子段,平均数不小于二分的值𝑚

▪ 判定方法:

▪ 把数列中每个数都减去平均值,问题变为是否存在长度不小于𝐿 的子段,子段和非负

▪转化为前缀和相减的形式𝑠𝑢𝑚 𝑖 − min 0≤𝑗≤𝑖−𝐿 𝑠𝑢𝑚 𝑗 ≥ 0

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 100005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int n,m;
32 double l=100000000,r=0;
33 double a[maxn],b[maxn],c[maxn];
34 
35 bool check(double x)
36 {
37     double temp=0,ans=-1000000;
38     for(int i=1;i<=n;i++)
39     {
40         b[i]=a[i]-x;
41         c[i]=c[i-1]+b[i];
42     }
43     for(int i=m;i<=n;i++)
44     {
45         temp=min(temp,c[i-m]);
46         ans=max(ans,c[i]-temp);
47     }
48     if(ans>=0) return 1;
49     else return 0;
50 }
51 
52 int main()
53 {
54     n=read();m=read();
55     for(int i=1;i<=n;i++)
56     {
57         scanf("%lf",&a[i]);
58         l=min(l,a[i]);
59         r=max(r,a[i]);
60     }
61     while(r-l>0.00001)
62     {
63         double mid=(l+r)/2;
64         if(check(mid))
65         {
66             l=mid;
67         }
68         else
69         {
70             r=mid;
71         }
72     }
73     cout<<(int)(r*1000)<<endl;
74     return 0;
75 }
View Code

 

2、双指针扫描

▪ Subsequence http://poj.org/problem?id=3061

▪ 给定序列 𝐴 和一个整数 𝑆,求一个长度最小的连续子段,使得子段和 ≥ 𝑆。

▪ 前缀和+ 二分 O (𝑛log𝑛)

▪ 双指针扫描 O (𝑛 )——枚举左端 𝑙,所求的子段右端 𝑟 是单调递增的

前缀和+ 二分 O 𝑛log𝑛:

 

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 100005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int t,n,m,l,r,aa; 
32 int a[maxn],b[maxn];
33 
34 bool check(int x)
35 {
36     int ans=0;
37     for(int i=x;i<=n;i++)
38     {
39         ans=max(ans,b[i]-b[i-x]);
40     }
41     if(ans>=m) return 1;
42     else return 0;
43 }
44 
45 int main()
46 {
47     t=read();
48     while(t--)
49     {
50         n=read();m=read();
51         for(int i=1;i<=n;i++)
52         {
53             aa=read();
54             a[i]=aa;
55             b[i]=b[i-1]+a[i];
56         }
57         if(b[n]<m)
58         {
59             printf("0\n");
60             continue;
61         }
62         l=1;r=n;
63         while(l<=r)
64         {
65             int mid=(l+r)>>1;
66             if(check(mid))
67             {
68                 r=mid-1;
69             }
70             else
71             {
72                 l=mid+1;
73             }
74         }
75         printf("%d\n",l);
76     }
77     return 0;
78 }
View Code

 

双指针扫描

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 100005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int t,n,m,aa,ans;
32 int a1,a2,pd;
33 int a[maxn],b[maxn];
34 
35 int main()
36 {
37     t=read();
38     while(t--)
39     {
40          n=read();m=read();
41          ans=1000000;
42          memset(a,0,sizeof(a));
43          memset(b,0,sizeof(b));
44          for(int i=1;i<=n;i++)
45          {
46              aa=read();
47              a[i]=aa;
48              b[i]=b[i-1]+a[i];
49          }
50          if(b[n]<m)
51         {
52              printf("0\n");
53              continue;
54         }
55          for(int i=1;i<=n;i++)
56         {
57             if(a[i]>=m)
58             {
59                 printf("1\n");
60                 pd=1;
61                 break;
62             }
63         }
64         if(pd==1)
65         {
66             pd=0;
67             continue;
68         }
69         a1=1;a2=1;
70         while(a1<=n&&a2<=n)
71         {
72             if(b[a2]-b[a1-1]>=m)
73             {
74                 ans=min(ans,a2-a1+1);
75                 a1++;
76             }
77             else
78             {
79                 a2++;
80             }
81         }
82         printf("%d\n",ans);
83     }
84     return 0;
85 }
View Code

 

▪ Costume Party http://poj.org/problem?id=3663

▪ 给定序列 𝐴 和一个整数 𝑆,求有多少对 𝑖,𝑗 满足 𝐴𝑖 + 𝐴𝑗 ≤ 𝑆。

▪ 把序列 𝐴 排序

▪ 枚举 𝑖,满足要求的 𝑗 的右端位置是单调递减的

双指针扫描:一个指针指向第一个元素,另一个指向最后一个元素,然后向中间间移动指针并累加个数。

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn  20005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int n,m,a1,a2,ans,aa;
32 int a[maxn];
33 
34 int main()
35 {
36     n=read();m=read();
37     for(int i=1;i<=n;i++)
38     {
39         aa=read();
40         a[i]=aa;
41     }
42     sort(a+1,a+1+n);
43     a1=1;a2=n;
44     while(a1<a2)
45     {
46         if(a[a1]+a[a2]<=m)
47         {
48             ans+=a2-a1;
49             a1++;
50         }
51         else
52         {
53             a2--;
54         }
55     }
56     cout<<ans;
57     return 0;
58 }
View Code

二分做法:先排序,再枚举 i ∈ [1,n-1] ,二分查找第一个j使得a[i]+a[j]<=s,然后ans+=j-i;

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 1000005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int n,m,aa;
32 long long ans;
33 int a[maxn];
34 
35 int main()
36 {
37     n=read();m=read();
38     for(int i=1;i<=n;i++)
39     {
40         aa=read();
41         a[i]=aa;
42     }
43     sort(a+1,a+1+n);
44     for(int i=1;i<n;i++)
45     {
46         int l=i+1,r=n;
47         while(l<=r)
48         {
49             int mid=(l+r)>>1;
50             if(a[i]+a[mid]<=m)
51             {
52                 l=mid+1;
53             }
54             else
55             {
56                 r=mid-1;
57             }
58         }
59         ans+=(long long)r-i;
60     }
61     cout<<ans;
62     return 0;
63 }
View Code

 

3、前缀和与差分

前缀和:

▪ 对于一个给定的数列A,它的前缀和数列S是通过递推能求出的基本信息之一:

▪ 𝑆[𝑖] = σ𝑗=1 𝑖 𝐴[𝑗]
▪ 一个部分和,即数列A中某个下标区间内的数的和,可以表示为前缀和相减的形式:

▪ sum 𝑙,𝑟 = σ𝑖=𝑙 𝑟 𝐴 𝑖 = 𝑆 𝑟 − 𝑆[𝑙 − 1]
▪ 在二维数组(矩阵)中,也有类似的递推形式,可求出二维前缀和,进一步计算出二维 部分和。

 

差分: 

▪ 长度为 𝑛 的序列 𝐴 的差分序列是一个长度为𝑛 的序列 𝐵

▪ 其中 𝐵1 = 𝐴1,𝐵𝑖 = 𝐴𝑖 − 𝐴𝑖−1 2 ≤ 𝑖 ≤ 𝑛
▪ 差分序列 𝐵 的前缀和数组就是原序列𝐴

▪ 把 𝐴 的区间 [𝑙,𝑟] 加 𝑑,𝐵 的变化为:𝐵𝑙 加 𝑑,𝐵𝑟+1 减 𝑑

 

P2280 [HNOI2003]激光炸弹

输入输出格式

输入格式:

输入文件名为input.txt

输入文件的第一行为正整数n和正整数R,接下来的n行每行有3个正整数,分别表示 xi,yi ,vi 。

输出格式:

输出文件名为output.txt

输出文件仅有一个正整数,表示一颗炸弹最多能炸掉地图上总价值为多少的目标(结果不会超过32767)。

输入输出样例

输入样例#1:
2 1
0 0 1
1 1 1
输出样例#1:
1
先预处理出矩阵的二维前缀和,然后枚举选用矩阵的右下角,利用二维前缀和公式,
统计最大值,由于矩阵的边缘不能取,注意一下边界,可以将给定矩阵长和宽各减一。
 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 5505
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int n,m,h,x;
32 int aa,bb,cc;
33 int ju[maxn][maxn];
34 int ans;
35 
36 int main()
37 {
38     n=read();m=read();
39     for(int i=1;i<=n;i++)
40     {
41         aa=read();bb=read();cc=read();
42         aa++;bb++;
43         ju[aa][bb]+=cc;
44     }
45     for(int i=1;i<=5001;i++)
46     {
47         for(int j=1;j<=5001;j++)
48         {
49             ju[i][j]+=ju[i-1][j]+ju[i][j-1]-ju[i-1][j-1];
50         }
51     }
52     for(int i=m;i<=5001;i++)
53     {
54         for(int j=m;j<=5001;j++)
55         {
56             ans=max(ans,ju[i][j]-ju[i-m][j]-ju[i][j-m]+ju[i-m][j-m]);
57         }
58     }
59     cout<<ans;
60     return 0;
61 }
View Code

 


P4552 [Poetize6] IncDec Sequence

题目描述

给定一个长度为n的数列a1,a2,,an,每次可以选择一个区间[l,r],使这个区间内的数都加1或者都减1。

请问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。

输入输出格式

输入格式:

第一行一个正整数n
接下来n行,每行一个整数,第i+1行的整数表示ai

输出格式:

第一行输出最少操作次数
第二行输出最终能得到多少种结果

输入输出样例

输入样例#1: 
4
1
1
2
2
输出样例#1: 
1
2

说明

对于100%的数据,n≤100000,0≤ai≤2147483648

首先维护一个差分序列,我们可以发现,如果修改区间[i,j],那么在差分序列上只会修改i和j+1的值,

并且i和j+1的操作相反,由于我们最终要让差分序列变成全0序列,所以我们要优先考虑正负数互相抵消的情况,

也就是说我们让正数减去1,让负数加上1,这样我们一定会向目标靠近一步,最后我们在单独处理剩余的正数或者负数,所以说,进行的操作总是就是差分

序列中正数和与负数和的绝对值的最大值。至于第二问,由于正负数抵消的环节是必不可少的,所以我们只考虑单独处理的这一阶段,由于差分序列是同号的,

所以这个差分序列的原序列一定是单调的,所以可以从前往后操作,也可以从后往前操作,这样得出的结果就是正数和与负数和之差的绝对值+1;

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 100005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 long long a1,a2;
32 long long n,aa,ans1,ans2;
33 int a[maxn],b[maxn];
34 
35 int main()
36 {
37     n=read();
38     for(int i=1;i<=n;i++)
39     {
40         aa=read();
41         a[i]=aa;
42         b[i]=a[i]-a[i-1];
43     }
44     for(int i=2;i<=n;i++)
45     {
46         if(b[i]<0)
47         ans1+=b[i]*(-1);
48         if(b[i]>0)
49         ans2+=b[i];
50     }
51     a1=max(ans1,ans2);
52     cout<<a1<<endl;
53     cout<<abs(ans1-ans2)+1;
54     return 0; 
55 }
View Code

 

P2879 [USACO07JAN]区间统计Tallest Cow

▪ 有N 头牛站成一行。两头牛能够相互看见,当且仅当它们中间的牛身高都比它们矮。

▪ 我们只知道其中最高的牛是第P 头,它的身高是H,不知道剩余 𝑁 − 1 头牛的身高。

▪ 我们还知道M 对关系,每对关系都指明了某两头牛𝐴𝑖 和 𝐵𝑖 可以相互看见。

▪ 求每头牛的身高最大可能是多少。

▪ 1 ≤ 𝑁,𝑀 ≤ 104,1 ≤ 𝐻 ≤ 106

 

▪ 建立一个数组𝐶,数组中起初全为0。

▪ 若一条关系指明𝐴𝑖 和 𝐵𝑖 可以互相看见(不妨设𝐴𝑖 < 𝐵𝑖),则把数组𝐶 中下标为 𝐴𝑖 + 1 到 𝐵𝑖 − 1 的数都减去1,意思是在𝐴𝑖 和 𝐵𝑖 中间的牛,身高至少要比它们小1。

▪ 由于第P头牛是最高的,所以最终 𝐶[𝑃] 一定为0,第 𝑖 头牛的身高就等于𝐻 + 𝐶[𝑖]。
▪ 可转化为建立一个数组𝐷,对于每对 𝐴𝑖 和 𝐵𝑖,令 𝐷[𝐴𝑖 + 1] 减去1,𝐷[𝐵𝑖] 加上1。

▪ 其含义是:“身高减小1”的影响从𝐴𝑖 + 1 开始,持续到𝐵𝑖 − 1,在 𝐵𝑖 结束。

▪ 最后,𝐶 就等于 𝐷 的前缀和。

注意一下,由于这道题的输入数据有重复,所以要去重。方法很简单,开一个map由pair映射到bool判断一下就行了。

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #include<set>
11 #define maxn 10005
12 using namespace std;
13 
14 inline int read()
15 {
16     char c=getchar();
17     int res=0,x=1;
18     while(c<'0'||c>'9')
19     {
20         if(c=='-')
21         x=-1;
22         c=getchar();
23     }
24     while(c>='0'&&c<='9')
25     {
26         res=res*10+(c-'0');
27         c=getchar();
28     }
29     return x*res;
30 }
31 
32 int n,p,m,h,aa,bb;
33 int a[maxn],b[maxn];
34 map<pair<int,int>,bool>s;
35 
36 int main()
37 {
38     n=read();p=read();h=read();m=read();
39     for(int i=1;i<=n;i++)
40     {
41         a[i]=h;
42         b[i]=a[i]-a[i-1];
43     }
44     for(int i=1;i<=m;i++)
45     {
46         aa=read();bb=read();
47         if(s[make_pair(aa,bb)]) continue;
48         s[make_pair(aa,bb)]=1;
49         if(aa>bb)
50         swap(aa,bb);
51         b[aa+1]--;
52         b[bb]++;
53     }
54     for(int i=1;i<=n;i++)
55     {
56         b[i]=b[i-1]+b[i];
57         printf("%d\n",b[i]);
58     }
59     return 0;
60 }
View Code

 

4、贪心

CF444A DZY Loves Physics

题目大意:给定一个无向图,定义一个图的联通导出子图的密度为其点权之和除以边权之和。(注:边权之和为零的图密度为零)求该图的联通导出子图的最大密度。一个图的导出子图是指,选取一个顶点集,以两端点均在该顶点集中的边的全体为边集的子图。

输入格式:第一行两个整数n (1<=n<=500) ,m(0<=m<=n(n-1)/2),分别表示图的节点数和边数。第二行n个整数xi(1<=xi<=1000000)表示第i个点的权值。后m行每行三个整数ai,bi,ci,(1<=ai,bi<=n;1<=ci<=1000)表示从ai到bi有一条权值为ci的无向边。数据保证无重边。

输出:一个浮点数,表示该图的联通导出子图密度的最大值,保留小数点后15位。如果你的答案和标准答案相差不超过10e-9,则被认为是正确的。

 

比较 𝑥+𝑦/𝑝, 𝑦+𝑧/𝑞和 𝑥+𝑦+𝑧/ 𝑝+𝑞

▪𝑥+𝑦+𝑧/𝑝+𝑞不可能是三者中的最大值
▪ 故所求的子图必然由两个点和一条边构成

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 250005
11 using namespace std;
12 
13 inline int read()
14 {
15     char c=getchar();
16     int res=0,x=1;
17     while(c<'0'||c>'9')
18     {
19         if(c=='-')
20         x=-1;
21         c=getchar();
22     }
23     while(c>='0'&&c<='9')
24     {
25         res=res*10+(c-'0');
26         c=getchar();
27     }
28     return x*res;
29 }
30 
31 int n,m,aa,bb,cc;
32 int a[maxn],b[maxn];
33 double ans;
34 
35 int main()
36 {
37     n=read();m=read();
38     for(int i=1;i<=n;i++)
39     {
40         aa=read();
41         a[i]=aa;
42     }
43     for(int i=1;i<=m;i++)
44     {
45         aa=read();bb=read();cc=read();
46         if((double)(a[aa]+a[bb])/cc>ans)
47         {
48             ans=(double)(a[aa]+a[bb])/cc;
49         }
50     }
51     printf("%.15lf",ans);
52     return 0;
53 }
View Code

 

UVA1193 Radar Installation

描述:

假设海岸线是一条无限长的直线,陆地位于海岸线的一边,大海位于海岸线的另一边。大海中有许多小岛。某安全部门为了监视这些岛上是否有敌人入侵,打算在海岸线上安装若干个雷达来检测岛屿的情况。每个雷达的覆盖范围是以雷达中心为圆心,半径为d的圆形区域。

我们用平面之间坐标系来表示整个区域,海岸线为x轴,大海位于x轴上方,陆地位于x轴下方。为了节约成本,安全部门想使用最少的雷达覆盖所有的岛屿。现在已知每个岛屿的坐标(x,y)和雷达的覆盖半径d,你的任务就是计算出能够覆盖所有岛屿的最少雷达数量。

输入:

输入包含若干组数据。每组数据的第一行有两个整数n(1<=n<=1000)和d,分别表示岛屿的数量和雷达的覆盖半径,之后的n行,每行有两个整数,表示第i个岛屿的坐标(xi,yi),相邻的两组数据使用一个空行隔开。输入“0 0”表示输入结束。

输出:

对于每一组数据的输出格式为“Case i: x”,表示第i组数据中最少需要x个雷达来覆盖所有的岛屿;x=-1表示这组数据无解(无法覆盖所有的岛屿)

 

▪ 把 𝑥 轴上方的每个点转化为𝑥 轴上的一段能管辖它的区间𝑙[𝑖]~𝑟[𝑖]。

▪ 按照每个区间左端点的𝑥 坐标从小到大排序。

▪ 贪心,假如当前区间𝑖 的左端点坐标大于已经放置的任何一台设备,则新增一台。

▪ 否则就让上一台已安放的设备来管辖它,安放位置与𝑟[𝑖] 取min。

▪ 以此类推直至所有区间被管辖,输出设备个数即可。

 

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 #define maxn 1005
11 using namespace std;
12 
13 struct edge
14 {
15     double l,r;
16 }g[maxn];
17 
18 inline int read()
19 {
20     char c=getchar();
21     int res=0,x=1;
22     while(c<'0'||c>'9')
23     {
24         if(c=='-')
25         x=-1;
26         c=getchar();
27     }
28     while(c>='0'&&c<='9')
29     {
30         res=res*10+(c-'0');
31         c=getchar();
32     }
33     return x*res;
34 }
35 
36 int n,m,num,d,ans;
37 int aa,bb,pd;
38 
39 bool cmp(edge a,edge b)
40 {
41     return a.l<b.l;
42 }
43 
44 int main()
45 {
46     while(1)
47     {
48         n=read();d=read();
49         if(n==0&&d==0) break;
50         pd=0;
51         for(int i=1;i<=n;i++)
52         {
53             aa=read();bb=read();
54             if(bb>d) pd=1;
55             g[i].l=aa-sqrt((pow(d,2)-pow(bb,2)));
56             g[i].r=aa+sqrt((pow(d,2)-pow(bb,2)));
57         }
58         if(pd==1)
59         {
60             printf("Case %d: -1\n",++num);
61             continue;
62         }
63         else
64         {
65             sort(g+1,g+1+n,cmp);
66             double now=g[1].r;
67             ans=1;
68             for(int i=2;i<=n;i++)
69             {
70                 if(now<g[i].l)
71                 {
72                     ans++;
73                     now=g[i].r;
74                 }
75                 else
76                 {
77                     now=min(now,g[i].r);
78                 }
79             }
80         }
81         printf("Case %d: %d\n",++num,ans);
82     }
83     return 0;
84 }
View Code

 

CF865D Buy Low Sell High

▪ 已知 𝑁 天的股票价格,每天可以买入一股or 卖出一股or 什么也不做

▪ 𝑁 天后必须清仓,求最多能赚多少钱
▪ 贪心, O 𝑁log𝑁

▪ 从前往后扫描每一天的股价,维护一个小根堆

▪ 若堆中所有值都比当前股价高,则当前股价入堆

▪ 否则从堆顶那天买入(取出堆顶),从当前这天卖出(累加答案),并把当前这天的股 价入堆2 次

 1 #include<iostream>
 2 #include<string>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<map>
 7 #include<stack>
 8 #include<queue>
 9 #include<algorithm>
10 using namespace std;
11 
12 inline int read()
13 {
14     char c=getchar();
15     int res=0,x=1;
16     while(c<'0'||c>'9')
17     {
18         if(c=='-')
19         x=-1;
20         c=getchar();
21     }
22     while(c>='0'&&c<='9')
23     {
24         res=res*10+(c-'0');
25         c=getchar();
26     }
27     return x*res;
28 }
29 
30 priority_queue<int,vector<int>,greater<int> >q;
31 int n,aa;
32 long long ans;
33 
34 int main()
35 {
36     n=read();
37     for(int i=1;i<=n;i++)
38     {
39         aa=read();
40         if(q.empty())
41         {
42             q.push(aa);
43             continue;
44         }
45         int x=q.top();
46         if(aa>x)
47         {
48             ans+=(long long)aa-x;
49             q.pop();
50             for(int j=1;j<=2;j++)
51             q.push(aa);
52         }
53         else q.push(aa);
54     }
55     cout<<ans;
56     return 0;
57 }
View Code

 

 

posted @ 2019-01-30 20:37  snowy2002  阅读(613)  评论(1编辑  收藏  举报