【Codeforces #563 (Div. 2)】1174 A-F | 思维 | 贪心 | 素数筛 | 构造 | E

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 &lt; j ≤ n 1\le i &lt; j \le n 1i<jn,如果 a i + a j a_i+a_j ai+aj 是奇数,那么把他们交换,否则不交换。

求任意次操作后,整个数组所能达到的最小字典序。


[B] 思路

思维题。需要观察观察。

  • 如果整个数组都是奇数,或者都是偶数,那么无法进行任何操作,就直接输出。

  • 否则,我们必定可以通过有限次操作使数组达到其理论最小字典序(也就是升序排列)。

    下面证明:(对于原数组中的每个元素,称其在排序后数组中的位置为目标位置

    • 1.我们先看看只有一个奇数剩下都是偶数的情况。显然,通过这一个奇数不断地先和目标位置交换再和对应偶数元素交换,我们可以把偶数全部放到其目标位置。然后最后这个奇数也会自动地待在他的目标位置上了。因此此时可以达到理论最小字典序,也就是升序。
    • 2.如果奇数有 k &gt; 1 k&gt;1 k>1 个,那么也类似。我们可以先利用所有偶数把 k − 1 k-1 k1 个奇数放到他们的目标位置上去,然后再用剩下的一个奇数把所有偶数放到其目标位置上去,因此也能达到升序。

因此如果原数组既有奇数又有偶数,那么就排升序输出即可;否则就无法进行操作,就只能直接输出原数组。

时间复杂度: 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 2n2 个数中,对于每个数 p p p有且仅有一个 q q q,使得 p ⊗ q = x p\otimes q = x pq=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=xp,如果 p &lt; q p&lt;q p<q 则把这个 p p p 放入 s [   ] s[\ ] s[ ] 就得解了。(这样刚好能选出上面那个二分图某一侧的所有点,因为我们不妨设对于每条连线使 p i &lt; q i p_i&lt;q_i pi<qi。注意 p i   ! = q i p_i\ !=q_i pi !=qi,否则他们的异或和就是 0 0 0 了,而 x &gt; 0 x&gt;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 1n3×105),第 i i i 个数 a i a_i ai 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1ai109)表示有 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(ij) 这么三条边。

由此可见,越短的边被利用的可能性越大,而越往后落单的边就越不容易被再利用。

一个极端的例子是:边条数分别是 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;
}




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值