wtcl qwq
【CodeForces 1174 A-F】
Tags:思维 贪心 素数筛 构造 前缀和
A. Ehab Fails to Be Thanos
[A] 题意
给定一个数组有 2 n ( n ∈ [ 1 , 1000 ] ) 2n\ (n\in[1, 1000]) 2n (n∈[1,1000]) 个数,可任意重排数组,问是否能在重排后使得前 n n n 个数之和不等于后 n n n 个数之和。
[A] 思路
贪心地考虑,原数组重排后前后两段之和差距最大当且仅当重排后数组变得有序。所以我们康康排序后前 n n n 个和后 n n n 个之和是否相等即可。
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
[A] 代码
#include <cstdio>
#include <algorithm>
#define LL long long
#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define LL long long
#define ULL unsigned LL
#define PC putchar
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define UPL(_) UPRT(_),PC(10)
template<class T>
void PRT(const T _){if(_<0){PC(45),UPRT<ULL>(-(ULL)_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
#define PL(_) PRT(_),PC(10)
constexpr int MN(1e6+7);
int a[MN];
int main()
{
get(n)
int nn = n*2;
sc(a, nn)
std::sort(a, a+nn);
LL s1 = 0, s2 = 0;
F(i, nn)
if (i < n)
s1 += a[i];
else
s2 += a[i];
if (s1 == s2)
puts("-1");
else
F(i, nn)
PRT(a[i]), PC(32);
return 0;
}
B. Ehab Is an Odd Person
[B] 题意
给定一个数组(个数 ∈ [ 1 , 1 0 5 ] \ \in[1, 10^5] ∈[1,105]),你可以进行任意次这种操作:选择 1 ≤ i < j ≤ n 1\le i < j \le n 1≤i<j≤n,如果 a i + a j a_i+a_j ai+aj 是奇数,那么把他们交换,否则不交换。
求任意次操作后,整个数组所能达到的最小字典序。
[B] 思路
思维题。需要观察观察。
-
如果整个数组都是奇数,或者都是偶数,那么无法进行任何操作,就直接输出。
-
否则,我们必定可以通过有限次操作使数组达到其理论最小字典序(也就是升序排列)。
下面证明:(对于原数组中的每个元素,称其在排序后数组中的位置为目标位置)
- 1.我们先看看只有一个奇数剩下都是偶数的情况。显然,通过这一个奇数不断地先和目标位置交换再和对应偶数元素交换,我们可以把偶数全部放到其目标位置。然后最后这个奇数也会自动地待在他的目标位置上了。因此此时可以达到理论最小字典序,也就是升序。
- 2.如果奇数有 k > 1 k>1 k>1 个,那么也类似。我们可以先利用所有偶数把 k − 1 k-1 k−1 个奇数放到他们的目标位置上去,然后再用剩下的一个奇数把所有偶数放到其目标位置上去,因此也能达到升序。
因此如果原数组既有奇数又有偶数,那么就排升序输出即可;否则就无法进行操作,就只能直接输出原数组。
时间复杂度:
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
[B] 代码
#include <cstdio>
#include <algorithm>
#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define LL long long
#define ULL unsigned LL
#define PC putchar
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define UPL(_) UPRT(_),PC(10)
template<class T>
void PRT(const T _){if(_<0){PC(45),UPRT<ULL>(-(ULL)_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
#define PL(_) PRT(_),PC(10)
constexpr int MN(1e6+7);
int a[MN];
int main()
{
bool odd = false, even = false;
get(n)
F(i, n)
{
sc(a[i])
if (a[i] & 1) odd = true;
else even = true;
}
if (odd && even)
std::sort(a, a+n);
F(i, n)
PRT(a[i]), PC(32);
return 0;
}
C. Ehab and a Special Coloring Problem
[C] 题意
给定数组长度 n ∈ [ 1 , 1 0 5 ] n \in [1, 10^5] n∈[1,105]
你需要构造出这个数组 a [ ] a[\ ] a[ ],使其满足如下性质:
- 任选 i , j ∈ [ 2 , n ] i, j \in [2, n] i,j∈[2,n],如果 i , j i, j i,j 互质 那么 a [ i ] ! = a [ j ] a[i]\ !=a[j] a[i] !=a[j]
求在所有可能的构造方案中,数组中的最大值最小的那种方案。如果有多种,输入任意一个。
[C] 思路
可不是二分答案哦… 这里可以直接贪心解决。
两个数是互素的,当且仅当他们的素因子集合无交集。
这使我们想到了素数的素因子筛法…
因此只要在筛素数的时候顺便打上时间戳就行啦~
时间复杂度:如果是埃氏筛就是 O ( n l o g l o g n ) O(nloglogn) O(nloglogn)
[C] 代码
#include <cstdio>
#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define LL long long
#define ULL unsigned LL
#define PC putchar
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define UPL(_) UPRT(_),PC(10)
template<class T>
void PRT(const T _){if(_<0){PC(45),UPRT<ULL>(-(ULL)_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
#define PL(_) PRT(_),PC(10)
constexpr int MN(3e5+7);
int a[MN<<1];
int main()
{
int time = 0;
for (int i=2; i<MN; ++i)
if (!a[i] && ++time)
for (int k=i; k<MN; k+=i)
if (!a[k])
a[k] = time;
get(n)
FD(i, 2, n)
PRT(a[i]), PC(32);
return 0;
}
D. Ehab and the Expected XOR Problem
[D] 题意
给出两个数 n , x n, x n,x, n ∈ [ 1 , 18 ] , x ∈ [ 1 , 2 18 ] n\in [1, 18],x\in [1, 2^{18}] n∈[1,18],x∈[1,218]。
要构造数组 a [ ] a[\ ] a[ ],使其满足如下性质:
- 1.每个数均 ∈ [ 1 , 2 n ] \in[1, 2^n] ∈[1,2n]
- 2.该数组的任意非空连续子段的异或和不能等于 0 0 0 或 x x x
求在所有可能的构造方案中,数组长度最长的那个。
如果有多组解,输出任意一组。先输出长度,如果长度不为零则在第二行输出整个数组。
[D] 思路
首先,看见连续子段和,就应该想到前缀和。
那么第二种限制就变成了:对于该数组 a [ ] a[\ ] a[ ] 的异或前缀和数组 s [ ] s[\ ] s[ ] ,任何一个数都不能为 0 0 0 或 x x x,且任选两个数做异或也不能等于 0 0 0 或 x x x。
这样就把一个有序的限制转化为了无序的,同时把研究对象从一个区间转化成了两个点。要构造 a [ ] a[\ ] a[ ],我们不但要给出每个元素的值,还要给出他们的位置,使得这些值按照这种位置排布时满足题给限制(且限制对象是一些长度和位置都可变的区间);而要构造 s [ ] s[\ ] s[ ],我们只需要确定每个元素的值即可,因为前缀和需要满足的限制和元素位置无关,且限制是针对每一对元素的。这样问题就得到了转化和简化,同时也提高了可操作性。解法虽然简单,但这种简化问题的思维应该牢记。
再回到问题中来。我们构造出 s [ ] s[\ ] s[ ] 后就构造出了 a [ ] a[\ ] a[ ] 吗?
是的。只要求和运算及其逆运算的定义是二元函数(给定两个算子,其运算结果唯一),那么前缀和数组和原数组就是唯一对应的。并且他们的长度也是相同的。
因此现在我们需要构造出尽可能长的 s [ ] s[\ ] s[ ] 。
考虑到原数组每个数的二进制位数不超过 n n n,因此异或和位数也不超过 n n n。又因为异或和不能是 0 0 0 或 x x x,因此异或和范围就是 [ 1 , x ) ∪ ( x , 2 n ) [1, x) \cup (x, 2^n) [1,x)∪(x,2n)。
又因为 s [ ] s[\ ] s[ ] 中任选两个数异或和不能是 0 0 0,因此 s [ ] s[\ ] s[ ] 中的数值都是互异的。因此相当于我们要从 [ 1 , x ) ∪ ( x , 2 n ) [1, x) \cup (x, 2^n) [1,x)∪(x,2n) 中选出尽可能多的互异的数,且保证在它们之间任选两个数的异或和不能等于 x x x。选出来之后,随便把它们排成一排,就是最长的满足限制条件的异或和数组了。然后再反推回原数组即可得到答案。
那么怎么选呢?可以发现这个问题实质是在集合中选尽量多的元素,且有一些“选了A则不能选B”的限制。这不就是个二分图最大独立点集吗?那是不是直接上网络流?大可不必。(但是博主这几天学网络流都魔怔了qwq 什么都想网络流 )因为在
[
1
,
x
)
∪
(
x
,
2
n
)
[1, x) \cup (x, 2^n)
[1,x)∪(x,2n) 这
2
n
−
2
2^n-2
2n−2 个数中,对于每个数
p
p
p 都有且仅有一个数
q
q
q,使得
p
⊗
q
=
x
p\otimes q = x
p⊗q=x。所以那个二分图其实应该是长这样的:
那还网啥流?直接枚举
[
1
,
x
)
∪
(
x
,
2
n
)
[1, x) \cup (x, 2^n)
[1,x)∪(x,2n) 中所有数,对于每个数
p
p
p 算出
q
=
x
⊗
p
q=x\otimes p
q=x⊗p,如果
p
<
q
p<q
p<q 则把这个
p
p
p 放入
s
[
]
s[\ ]
s[ ] 就得解了。(这样刚好能选出上面那个二分图某一侧的所有点,因为我们不妨设对于每条连线使
p
i
<
q
i
p_i<q_i
pi<qi。注意
p
i
!
=
q
i
p_i\ !=q_i
pi !=qi,否则他们的异或和就是
0
0
0 了,而
x
>
0
x>0
x>0。)
时间复杂度: O ( 2 n ) O(2^n) O(2n)
[D] 代码
#include <cstdio>
#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define LL long long
#define ULL unsigned LL
#define PC putchar
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define UPL(_) UPRT(_),PC(10)
template<class T>
void PRT(const T _){if(_<0){PC(45),UPRT<ULL>(-(ULL)_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
#define PL(_) PRT(_),PC(10)
constexpr int MN(1<<19);
int s[MN];
int main()
{
get(n, x)
int tot = 0;
for (int i=1, max_v=1<<n; i<max_v; ++i)
{
if (i == x)
continue;
int p = i, q = x ^ p;
if (p < q)
s[tot++] = p;
}
PL(tot);
FD(i, 1, tot)
PRT(s[i] ^ s[i-1]), PC(32);
return 0;
}
E. Pavel and Triangles
[E] 题意
给定 n n n 个数( 1 ≤ n ≤ 3 × 1 0 5 1\le n \le 3\times 10^5 1≤n≤3×105),第 i i i 个数 a i a_i ai( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109)表示有 a i a_i ai 条长为 2 i 2^i 2i 的边。
问用这么多条边最多可以组成多少个 △ △ △。
[E] 思路
首先,简单推一下就能发现,如果要组成三角形,要么选 2 i , 2 i , 2 i 2^i, 2^i, 2^i 2i,2i,2i 三条等长的边,要么选 2 i , 2 j , 2 j ( i ≤ j ) 2^i, 2^j, 2^j(i\le j) 2i,2j,2j(i≤j) 这么三条边。
由此可见,越短的边被利用的可能性越大,而越往后落单的边就越不容易被再利用。
一个极端的例子是:边条数分别是 a , b , c , d , . . . , 4 a, b, c, d, ..., 4 a,b,c,d,...,4。如果拿了最后 4 4 4 中的 3 3 3 条,那剩的 1 1 1 就永远也用不上了。这样很有可能就不是最优解了(只要前面边条数之和大于2,就能找到一定不会更差的取法因为利用率一定不会降低)
为了防止这一点,我们从前往后遍历,同时记录当前落单的边的条数,每次遍历到新的长度的时候首先尽可能多地“消灭”以前落单的,如果这次不够消灭完,就剩一点然后也并入落单的里面去;如果这次消灭完还有剩,那么为了尽可能少地为后面带来落单的边,应该尽可能多地自我组合(用 3 3 3 条自己组成三角形),然后组合不了的就计入落单的边。
这样遍历一遍就求出答案了。
时间复杂度: O ( n ) O(n) O(n)
[E] 代码
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<string>
#include<algorithm>
#include<utility>
#include<vector>
#include<list>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<bitset>
#include<cctype>
#include<climits>
#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<n;++i)
#define _FLR(i,l,r) for(auto i=l,_r=r;i<_r;++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=n;++i)
#define _FDL(i,l,r) for(auto i=l,_r=r;i<=_r;++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define OPER1(T,x1,b1) inline bool operator<(const T&o)const{return x1 b1 o.x1;}
#define OPER2(T,x1,b1,x2,b2) inline bool operator<(const T&o)const{return x1 b1 o.x1||x1==o.x1&&x2 b2 o.x2;}
#define OPER3(T,x1,b1,x2,b2,x3,b3) inline bool operator<(const T&o)const{return x1 b1 o.x1||x1==o.x1&&(x2 b2 o.x2||x2==o.x2&&x3 b3 o.x3);}
#define LL long long
#define ULL unsigned long long
#define PC putchar
template<class T>
void PRT(const T _){if(_<0){PC(45),PRT(-_);return;}if(_>=10)PRT(_/10);PC(_%10+48);}
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}
#define CON constexpr
#define T_CASE int CASE;sc(CASE)for(int __=1;__<=CASE;++__)
#define cincout std::cin.tie(nullptr),std::cout.tie(nullptr),std::ios::sync_with_stdio(false);
#define eps 1e-8
#define PI 3.141592653589793
#define MAX_INT 2147483647
#define MIN_INT -2147483648
#define MAX_LL 9223372036854775807
#define MIN_LL -9223372036854775808
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3fLL
#define endl '\n'
#define priority_queue priority_queue
#define PQ std::priority_queue
#define PR std::pair
#define vector vector
#define VI std::vector<int>
#define MII std::map<int,int>
#define MLI std::map<LL,int>
#define MSI std::map<std::string,int>
#define PII std::pair<int,int>
#define PLI std::pair<LL,int>
#define PSI std::pair<std::string,int>
#define MPFD(k) auto it=mp.find(k)
#define MIN(a, b) ((a)<(b)?(a):(b))
#define MIN3(a, b, c) (MIN(a, MIN(b, c)))
#define MAX(a, b) ((a)>(b)?(a):(b))
#define MAX3(a, b, c) (MAX(a, MAX(b, c)))
#define get_max(a,l,r,_max) auto _max=a[l];for(int _i=l+1,_r=r;_i<_r;++_i)if(_max<a[_i])_max=a[_i]
#define get_min(a,l,r,_min) auto _min=a[l];for(int _i=l+1,_r=r;_i<_r;++_i)if(_min<a[_i])_min=a[_i]
#define ABS(a) ((a)>0?(a):-(a))
#define FABS(a) ((a)>0?(a):-(a))
#define log2n(x) (log(x)/0.69314718055995)
#define MHD(p1, p2) ((p1.x>p2.x?p1.x-p2.x:p2.x-p1.x)+(p1.y>p2.y?p1.y-p2.y:p2.y-p1.y))
#define PB emplace_back
#define EB emplace_back
#define BRK else break
#define ALL(X) (X).begin(),(X).end()
#define SORT(X) std::sort(ALL(X))
#define SORTD(X) std::sort(ALL(X),std::greater<decltype((X)[0])>())
#define swap(a, b) do{auto _t=a; a=b; b=_t;}while(0)
#define mem0(a) memset(a,0,sizeof(a))
#define memf1(a) memset(a,-1,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
int main()
{
int res = 0;
LL sum = 0;
get(n)
F(i, n)
{
get(tp)
if (tp >= 2*res) // 还有余
{
tp -= 2*res;
sum += res; // 凑了res个三角形
sum += tp/3, res = tp%3; // 甚至还可以内部再组装
}
else // 不够
{
res -= tp/2; // 一共就tp/2对,凑了tp/2个三角形
sum += tp/2; // 凑了tp/2个三角形
res += tp&1; // 如果是奇数,就还剩1个,也加上,后面人可以用
}
}
UPRT(sum);
return 0;
}