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 }
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 }
双指针扫描:

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 }
▪ 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 }
二分做法:先排序,再枚举 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 }
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)。
输入输出样例
2 1 0 0 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 }
P4552 [Poetize6] IncDec Sequence
题目描述
给定一个长度为n的数列a1,a2,⋯,an,每次可以选择一个区间[l,r],使这个区间内的数都加1或者都减1。
请问至少需要多少次操作才能使数列中的所有数都一样,并求出在保证最少次数的前提下,最终得到的数列有多少种。
输入输出格式
输入格式:第一行一个正整数n
接下来n行,每行一个整数,第i+1行的整数表示ai。
第一行输出最少操作次数
第二行输出最终能得到多少种结果
输入输出样例
4 1 1 2 2
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 }
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 }
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 }
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 }
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 }
来源:https://www.cnblogs.com/snowy2002/p/10339727.html
