ABC388

好像已经很久没有写过题解了

C

link

对于每一个糕点,二分查找大于等于它大小的二倍的糕点的位置(可以用\(lower_{}bound\)函数),从这个位置到\(n\)就是可以和这个糕点配对的糕点。

猜猜我是啥
#include<bits/stdc++.h>

#define int long long

using namespace std;

int n;
int a[500005];
int ans;

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		cin >> a[i];
	
	for(int i = 1;i <= n;++ i){
		int w = a[i]*2;
		int wz = lower_bound(a+1,a+1+n,w)-a;
		ans += n-wz+1;
	}
	
	cout << ans;
	
	return 0;
	
}

D

link

\(d_i\)\(i\)成年时有的石头数。
首先我们可以得出,石头只会从前往后送;而且我们还可以得出,\(i\)成年后一共会送出\(min(a_i,n-i)\)个石头,也就是会让\(i+1\)\(i+min(a_i,n-i)\)这些人的石头数加一。
我们知道,区间加一可以用差分,可是差分要全做完之后做前缀和才能知道结果,怎么办呢?我们知道如果一个数成年了就不会再得到石头了,也就是说当我们需要知道\(d_i\)时,它就不会再改变了,那么我们就可以边差分边前缀和,做到哪一个需要它了就算到这个的前缀和,后面还是用差分去做区间加一。

猜猜我是啥
#include<bits/stdc++.h>

using namespace std;

int n;
int a[500005];
int cf[500005];

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		cin >> a[i],cf[i] = a[i]-a[i-1];
	
	for(int i = 1;i <= n;++ i){
		a[i] = cf[i-1]+cf[i];
		cf[i] += cf[i-1];
		int w = min(a[i],n-i);
		cf[i+1]++;
		cf[i+w+1]--;
		a[i] -= w;
	}
	
	for(int i = 1;i <= n;++ i)
		cout << a[i] << " ";
	
	return 0;
	
}

E

link

二分答案,对于一个答案\(x\),我们考虑从前面选\(x\)个(最小的\(x\)个),从后面选\(x\)个(最大的\(x\)个),看看可不可以组起来(最小中最小的和最大中最小的组起来一直到最小中最大的和最大中最大的组起来),如果可以,就更大一些,如果不行就小一些。

猜猜我是啥
#include<bits/stdc++.h>

using namespace std;

int n;
int a[500005];

bool check(int x){
	for(int i = 1,j = n-x+1;i <= x;++ i,++ j){
		if(a[i]*2 > a[j]) return false;
	}
	return true;
}

signed main(){
	
	cin >> n;
	for(int i = 1;i <= n;++ i)
		cin >> a[i];
	
	int l = 0,r = n/2;
	while(l < r){
		int mid = (l+r+1)/2;
		if(check(mid)) l = mid;
		else r = mid-1;
	}
	cout << l;
	
	return 0;
	
}
posted @ 2025-01-13 10:12  我的晴语表  阅读(32)  评论(0)    收藏  举报