【Codeforces Global Round 2(1119)】A-E | 贪心 | 二分答案 | 规律 | STL | 前缀和 | E

啊啊啊啊啊啊啊啊啊竟然和tourist分到了一个room!!


【CodeForces 1119   A-E】


Tags:贪心 二分答案 规律 STL 前缀和




A. Ilya and a Colorful Walk


[A] 题意

给定 n n n 个数,每个数都 ∈ [ 1 ,   n ] \in [1,\ n] [1, n],求相距最远的两个不相等的数的距离( 3 ≤ n ≤ 3 × 1 0 5 3\le n\le 3\times 10^5 3n3×105

(保证至少有一对不相等的数)


[A] 思路

容易想到是 max ⁡ { \max\{ max{第一个数 和 最后一个不等于第一个数的数 的距离,最后一个数 和 第一个不等于最后一个数的数 的距离 } \} }

容易想到个鬼  还是tcl唉,A都WA掉了)

时间复杂度: O ( n ) O(n) O(n)



[A] 代码

#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))

CON int MN(1e6+7);


int a[MN];


int main()
{
	get(n)sc(a, n)
	
	int ans1 = 0, ans2 = 0;
	F(i, n)
	{
		if (a[i] != a[n-1])
		{
			ans1 = n-i-1;
			break;
		}
	}
	
	for (int i=n-1; i>=0; --i)
	{
		if (a[i] != a[0])
		{
			ans2 = i;
			break;
		}
	}
	
	UPRT(MAX(ans1, ans2));
	
	return 0;
}




B. Alyona and a Narrow Fridge


[B] 题意

给定冰箱的高度 1 ≤ h ≤ 1 0 9 1 \le h \le 10^9 1h109,和 1 ≤ n ≤ 1 0 3 1 \le n \le 10^3 1n103 个瓶子的高度( 1 ≤ a i ≤ h 1 \le a_i \le h 1aih

冰箱尺寸是 2 × h 2 \times h 2×h 的,瓶子尺寸是 1 × a i 1 \times a_i 1×ai的,

可以往冰箱里插入任意多块隔板,然后把第 1 1 1~ k k k 个瓶子放进冰箱(瓶子不能放叠在瓶子上方,只能放在隔板上方)

k k k 最大值。

在这里插入图片描述
  图例


[B] 思路

贪心 + 二分答案

显然最优的策略是空间浪费最少,所以就是尽量把高度相近的瓶子放在一起。

瓶子个数是偶数的时候很简单,排序然后取每一对的较大者相加再和 h h h 比即可,

是奇数的时候,则一定会剩一个。那当然是剩最矮的那个最合算(也可以看做它和 0 0 0 最近),所以也好验证。


外层二分区间就是 [ 0 , n − 1 ] [0, n-1] [0,n1]。内层判断就是排序+遍历求和。

时间复杂度: O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)



[B] 代码

#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))

CON int MN(1e6+7);


int a[MN];
int t[MN];
LL h;

bool check(int ans)
{
	int n = ans + 1;
	F(i, n)
		t[i] = a[i];
	std::sort(t, t+n);
	LL sum = h;
	for (int i=n-1; i>=0; i-=2)
		sum -= t[i];
	return sum >= 0;
}

int main()
{
	get(n)
	sc(h)sc(a, n)

	int L = 0, R = n-1;

	while (L <= R)
	{
		int mid = L+R>>1;
		if (check(mid))
			L = mid+1;
		else
			R = mid-1;
	}
	UPRT(R+1);

	return 0;
}




C. Ramesses and Corner Inversion


[C] 题意

给定两个 R × C R\times C R×C 01 01 01 矩阵 A A A B B B。( 1 ≤ R ,   C ≤ 500 1 \le R,\ C \le 500 1R, C500

可以进行一种操作是:选定 A A A 矩阵内部的某个面积至少是 2 × 2 2\times 2 2×2 的子矩阵,然后把这个子矩阵的四个角取逻辑反

问能否进行任意多次这种操作把 A A A 变成 B B B,可以输出 Yes,不可以输出 No。


[C] 思路

有点像开灯。我们做一个差异矩阵 D = A   x o r   B D = A\ xor\ B D=A xor B,通过观察我们可以发现如果 D D D 的某一行只有奇数个 1 1 1,那么就没法通过那种操作把 A A A 变成 B B B(因为每次变换必会把某两行的两个数给取反)

那么对称地,每列也是这样的。所以我们按行扫一轮再按列扫一轮这个 D D D 矩阵就行了。

时间复杂度: O ( n 2 ) O(n^2) O(n2)



[C] 代码

#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))

CON int MN(500+7);

int a[MN][MN], b[MN][MN], d[MN][MN];

int main()
{
	get(R, C)
	F(r, R)
		F(c, C)
			sc(a[r][c])
	F(r, R)
		F(c, C)
			sc(b[r][c])
	F(r, R)
		F(c, C)
			d[r][c] = a[r][c] ^ b[r][c];

	F(r, R)
	{
		int sum = 0;
		F(c, C)
			sum += d[r][c];
		if (sum & 1)
			return puts("No"), 0;
	}

	F(c, C)
	{
		int sum = 0;
		F(r, R)
			sum += d[r][c];
		if (sum & 1)
			return puts("No"), 0;
	}

	return puts("Yes"), 0;
}




D. Frets On Fire


[D] 题意

给出一个行数有限(记为 n n n 1 ≤ n ≤ 1 0 5 1 \le n \le 10^5 1n105)、列数无限的矩阵

并给定第 0 0 0 列元素 0 ≤ a [ i ] [ 0 ] ≤ 1 0 18 0 \le a[i][0] \le10^{18} 0a[i][0]1018

然后从第 1 1 1 列(含)开始,每一列的每一项都是由它左边那一列的每一项 +1 而得到。

比如:
在这里插入图片描述

然后询问 1 ≤ k ≤ 1 0 5 1 \le k \le 10^5 1k105 次,每次给出两个数 0 ≤ l k ≤ r k ≤ 1 0 18 0 \le l_k \le r_k \le 10^{18} 0lkrk1018,问第 l k l_k lk 列(含)到第 r k r_k rk 列(含)共有几个不同的数


[D] 思路

首先,某一列相同的数是可以去掉的(多个相同的数不会造成任何贡献)。

我们把每次生成新的一列称为一次更新。通过观察可以发现,当相邻两个数的差距是 d i s i = a [ i ] − a [ i − 1 ] dis_i = a[i] - a[i-1] disi=a[i]a[i1] 时,在 d i s i − 1 dis_i-1 disi1 以内次更新中,每次更新都会产生一个从来没出现的数(并且是这两个数之间的数);在超过这个更新次数之后,就不会再产生这两个数之间的、没出现过的数了。

比如数分别是 1 , 3 , 6 1,3,6 136,相邻数对的差距分别是 2 , 3 2,3 23,那么第一次更新的时候两个数对各会产生一个数对之间的数(第一对产生 2 ∈ ( 1 ,   3 ) 2\in(1,\ 3) 2(1, 3),第二对产生 4 ∈ ( 3 ,   6 ) 4\in(3,\ 6) 4(3, 6)),然后第二次更新的时候第一对数不再产生新数( ( 1 ,   3 ) (1,\ 3) (1, 3) 内的数已经全部产生完毕),而第二对数的间距大一点,还能再产生一个新数 5 ∈ ( 3 ,   6 ) 5\in(3,\ 6) 5(3, 6)。而等到第三次更新以及更之后的更新,两对数均不再产生处于相邻数对之间的新数了。

此外,除了这种方式会产生新数(相邻数对之间的新数),每次更新必定还会产生一个额外的新数(那个最大的、拓展出的数)

还是比如 1 , 3 , 6 1,3,6 136,那第一次更新会产生 7 7 7,第二次更新会产生 8 8 8。你已经发现了,这种新数每次更新都必然会产生一个。它不是夹在某个相邻数对之间的新数,它是由当前最大数再 + 1 +1 +1 而产生的新数。


所以新数就是两大部分啦:

  • 1.每一对相邻数对之间的新数:如果给定更新次数 c n t = r k − l k cnt = r_k-l_k cnt=rklk,记满足 d i s i − 1 ≤ c n t dis_i-1 \le cnt disi1cnt 的最大的 i i i j j j
    • [ 1 ,   j ] [1,\ j] [1, j] 对相邻数对:他们的“潜能”已经被榨干了,他们之间的数已经全部产生,这部分新数有 ∑ i = 1 j ( d i s i − 1 ) \sum\limits_{i=1}^{j}(dis_i-1) i=1j(disi1)
    • [ j + 1 ,   n − 1 ] [j+1,\ n-1] [j+1, n1] 对相邻数对:他们的距离足够大(仍然具备潜能),所以每次更新都在产生新数。每次更新产生 n − 1 − j n-1-j n1j 个新数, c n t cnt cnt 次更新就产生 c n t × ( n − 1 − j ) cnt \times (n-1-j) cnt×(n1j) 个新数。

  • 2.每次更新产生的最大的那个新数(由上次最大数+1得到)
    • 每次更新总产生且仅产生一个。总个数显然是 c n t × 1 cnt \times 1 cnt×1

所以总次数就是 [ ∑ i = 1 j ( d i s i − 1 ) ]   +   [ c n t × ( n − 1 − j ) ]   +   [ c n t × 1 ] [\sum\limits_{i=1}^{j}(dis_i-1)]\ + \ [cnt \times (n-1-j)]\ +\ [cnt \times 1] [i=1j(disi1)] + [cnt×(n1j)] + [cnt×1]


那怎么求 j j j 呢? std::upper_bound 即可。

那求出 j j j 后怎么求和呢?预处理 前缀和 即可。



时间复杂度: O (   ( n + k ) log ⁡ n   ) O(\ (n+k)\log n\ ) O( (n+k)logn )



[D] 代码

#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))

CON int MN(2e5+7);


LL a[MN];
LL d[MN];
LL sum[MN];

int main()
{
	get(n)sc(a, n)
	std::sort(a, a+n);
	n = std::unique(a, a+n) - a;

	F(i, 1, n)
		d[i] = a[i] - a[i-1] - 1; // d[i] >= 0
	std::sort(d+1, d+n);

	F(i, 1, n)
		sum[i] = d[i] + sum[i-1];

	get(q)while (q--)
	{
		LL l, r;
		sc(l)sc(r)
		LL cnt = r-l;

		int k = std::upper_bound(d+1, d+n, cnt) - (d+1); // d[1, 2, ..., k]-1 <= cnt,这k对是没潜能的
		LL ans = n;				// 本来有多少个数
		ans += sum[k];			// 被"榨干"潜能的数对之间的数(总共产生前缀和这么多个)
		ans += cnt * (n-1-k);	// 还有潜能的数对之间的数(有几对,每次更新就产生几个)(共n个数,所以共n-1对。k对是没潜能的,n-1-k对是有潜能的)
		ans += cnt * 1;			// 每次产生的、非原来的数对之间的数(每次更新产生一个)

		UPRT(ans), 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;
}




(啊… 和tourist分在一个room真的超激动的… (虽然这场打得超烂,A题都FST了…
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值