Codeforces Round #645 (Div. 2) 题解 (全部6题)

https://codeforces.com/contest/1358

A. Park Lighting

输出 (lceil dfrac{ab}2 ceil)

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll;
#define int ll
int T,a,b;
signed main(){
	cin>>T;
	while(T--){
		cin>>a>>b;
		cout<<(a*b+1)/2<<endl;
	} 
	return 0;
}

B. Maria Breaks the Self-isolation

题面真长。排序,然后求 (a[1]+a[2]+...+a[i]<=i)(i) 的最大值

当然答案要加 (1) 因为要算上Maria

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll;
#define int ll
int T,n,a[N];
signed main(){
	cin>>T;
	while(T--){
		cin>>n;
		repeat(i,0,n)cin>>a[i];
		sort(a,a+n);
		int ans=1;
		repeat(i,0,n)if(a[i]<=i+1)ans=i+2; //我编号从0开始有点不同
		cout<<ans<<endl;
	} 
	return 0;
}

C. Celex Update

怎么说呢……比如要从1走到18,有这么两种走法

右图比左图数字之和刚刚好多了1。这说明一旦出现类似 (4, 7, 12) 这样的上三角形拐角,我们可以让它拐下来变成 (4,8,12)。这样操作 ((y_2-y_1)(x_2-x_1)) 次后就彻底找不到这种拐角了,因此答案是 ((y_2-y_1)(x_2-x_1)+1)

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=200010; typedef long long ll;
#define int ll
int T,x1,x2,y1,y2;
signed main(){
	cin>>T;
	while(T--){
		cin>>x1>>y1>>x2>>y2;
		cout<<(x2-x1)*(y2-y1)+1<<endl;
	}
	return 0;
}

D. The Best Vacation

最优解的区间的右端点一定一定是某个月的月末(这里的区间左右端点都表示某一天)。小证一下,假设有个右端点不是月末的区间,如果左端点(那一天的拥抱次数,下同)大于右端点就让它向左平移,如果左端点小于右端点就让它向右平移,这样总拥抱次数必定增大,因此结论成立qwq

这样就容易好多,我们枚举每个月的月末,二分查找区间左端点即可(不二分查找应该也可)

我这题fst了,尴尬至极,代码先删了避免误导(更:现在ac了,思路没问题放心食用)

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=400010; typedef long long ll;
#define int ll
int T,n,x,a[N],s[N],sum[N];
signed main(){
	cin>>n>>x;
	repeat(i,1,n+1){
		cin>>a[i];
		s[i]=s[i-1]+a[i];
		sum[i]=sum[i-1]+(1+a[i])*a[i]/2;
	}
	repeat(i,n+1,2*n+1){
		a[i]=a[i-n];
		s[i]=s[i-1]+a[i];
		sum[i]=sum[i-1]+(1+a[i])*a[i]/2;
	}
	n*=2;
	int ans=0;
	repeat(i,0,n+1){
		int p=upper_bound(s,s+n+1,s[i]-x)-s;
		if(p==0)continue;
		int t=s[i]-x-s[p-1];
		ans=max(ans,sum[i]-sum[p-1]-(1+t)*t/2);
	}
	cout<<ans<<endl;
	return 0;
}

E. Are You Fired?

官方题解写得好废脑,不看了,还是两位猛男 %lmj %kry 的思路清晰易懂

要分情况讨论,首先 (x>=0)(或 (x>0))时,判断所有数之和是否大于0,是就输出n,不是输出-1

  • 怎么证明呢?假设存在一个 (k<n) 的可行解,这意味着区间 ([1,k],[k+1,2k],...,[blabla,lfloor dfrac n k floor k]) 的区间和都大于0。取这 (lfloor dfrac n k floor) 个区间并在一起得到区间 ([1,lfloor dfrac n k floor k]),它一定覆盖了区间 ([1,lceildfrac n 2 ceil])想想是这样的,要证明估计要分类讨论就不证了),这个区间剩下的都有 (a[i]=x>=0)。因此 (k=n) 一定也是一个可行解。我们证明了只要有解,就一定存在 (k=n) 的解,那么这时只要输出n就行了

第二种情况是 (x<0)(或 (x<=0)),很快排除了 (kle lfloor dfrac n 2 floor) 的答案。这个情况猛男们的解法不完全一致,我分别介绍 (O(nlog n))(O(n)) 两种解法

  • (O(nlog n)) 解法:因为 (k>lfloor dfrac n 2 floor),右端点一定落在右半部分。我们可以枚举区间左端点,计算区间和为负数或者0时,对应的右端点的取值范围(不考虑右端点落在左半部分的情况的话,这个取值范围一定是一个区间),因此我们可以排除一些k的值,排除的值可以用树状数组维护。最后再找一遍合法的答案即可
  • (O(n)) 解法:滑动窗口。初始 ([l,r]) 覆盖了右半部分,如果 ([l,r]) 区间和小于等于0,那么不断l--,如果 ([l,r]) 区间和大于0,那么不断l--,r--(向左平移),向左平移到底了,那么这就是答案,但是一旦碰到了区间和小于等于0的情况,我们发现 ([l,r+1],[l,r+2],...,[l,n]) 区间和也同样小于等于0,这些答案((k=r-l+1...n-l+1))都瞬间蒸发,因此令 (r=n) 回到第一步继续搜索

(O(n)) 解法代码:

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=500010; typedef long long ll;
#define int ll
int T,n,x,a[N],S[N],*s=S+1;
signed main(){
	cin>>n;
	repeat(i,0,(n+1)/2)
		cin>>a[i],s[i]=s[i-1]+a[i];
	cin>>x;
	repeat(i,(n+1)/2,n)
		a[i]=x,s[i]=s[i-1]+a[i];
	if(x>=0)cout<<(s[n-1]>0?n:-1)<<endl,exit(0);
	
	auto calc=[](int l,int r){
		return s[r]-s[l-1];
	};
	int l=(n+1)/2,r=n-1;
	while(1){
		while(l>0 && calc(l-1,r)<=0)l--;
		if(l==0)cout<<-1<<endl,exit(0);
		l--;
		while(l>0 && calc(l-1,r-1)>0)l--,r--;
		if(l==0)cout<<r-l+1<<endl,exit(0);
		l--; r=n-1;
	}
	return 0;
}

我看了题解做的,这个表格有很大作用

然后然后,(nge 3) 的话就模拟好了。正着模拟有点不太行,倒着就非常清晰,因为前缀和一定是递增的。首先把 (b) 搞成递增(即每次如果 (b) 是递减就反转一下,如果既不递增也不递减就凉凉),然后在递增的前提下不断求 (b) 的差分。因为表格里的操作次数最多也就 1.5e6,再乘个常数,cf神机表示完全无压力

(n=2) 的话,一步步模拟肯定不行了,考虑类似求gcd的方法,跳着来就行了。(n=1) 再特判一下

最终,压行后的代码长这样:

#include <bits/stdc++.h>
using namespace std;
#define repeat(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define repeat_back(i,a,b) for(int i=(b)-1,_=(a);i>=_;i--)
int cansel_sync=(ios::sync_with_stdio(0),cin.tie(0),0);
const int N=500010; typedef long long ll;
#define int ll
int n,cnt;
vector<int> a,b;
deque<char> ans;
void rev(){ //反转b
	reverse(b.begin(),b.end());
	ans.push_front('R');
}
int ok(){ //判断a和b是否相等或者反转相等
	if(a==b)return 1;
	repeat(i,0,n)
		if(a[i]!=b[n-i-1])return 0;
	ans.push_front('R'); //反转当然要记录一下了
	return 1;
}
int down(){ //求差分,(n>=3)
	if(ok())return 1;
	if(b[0]>b[1])rev();
	repeat(i,0,n-1)if(b[i]>=b[i+1])return -1;
	repeat_back(i,1,n)b[i]-=b[i-1];
	ans.push_front('P'); cnt++;
	return 0;
}
void push(int x){ //求x次差分
	cnt+=x;
	b[1]-=b[0]*x;
	while(x--){
		if(ans.size()>N)return;
		ans.push_front('P');
	}
}
int down2(){ //求差分,(n==2)
	if(ok())return 1;
	if(b[0]>b[1])rev();
	if(a[0]>b[0] || a[1]>b[1])return -1;
	int t=max((b[1]-a[1])/b[0],1ll);
	push(t);
	return 0;
}
void output(int ok){ //输出
	if(ok){
		if(cnt<=200000){
			cout<<"SMALL"<<endl<<ans.size()<<endl;
			for(auto i:ans)cout<<i; cout<<endl;
		}
		else cout<<"BIG"<<endl<<cnt<<endl;
	}
	else cout<<"IMPOSSIBLE"<<endl;
}
signed main(){
	cin>>n; a=b=vector<int>(n);
	repeat(i,0,n)cin>>a[i];
	repeat(i,0,n)cin>>b[i];
	if(n==1)output(a[0]==b[0]);
	else if(n==2){
		int flag=0;
		if(a[0]>a[1]){ //先交换一下,方便判断
			swap(a[0],a[1]);
			flag=1;
		}
		int t;
		do t=down2(); while(t==0);
		if(flag)ans.push_front('R');
		output(t==1);
	}
	else{
		int t;
		do t=down(); while(t==0);
		output(t==1);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/axiomofchoice/p/12969835.html