[CF1148E]Earth Wind and Fire

题目

传送门 to luogu

思路

我们显然可以规定变化量 d = 1 d=1 ,但是多次操作。

当第 i i 小的元素增大到与第 i + 1 i+1 小的元素一样大时,如果我们继续增大第 i i 小的元素,完全可以改成增大第 i + 1 i+1 小的元素。这与增大第 i i 小的元素的效果相同。

所以我们得出结论,数字之间大小关系可以不发生改变

既然如此, s , t s,t 都可以排序。再给出以下结论:如果 s i > t i s_i>t_i ,则 一定可以必须 往前分摊。若无法分摊,则无解。这完全是“大小关系不改变”的推论。

代码实现很简单了,用 p p 存储最远的一个“坑”( s i < t i s_i<t_i 的地方)。显然,一次操作要么填满一个“坑”,要么让当前多出的部分全部消失,所以最多操作 n n 次。而 p p 的总移动复杂度也才 O ( n ) \mathcal O(n)

最终时间复杂度为 O ( n log n ) \mathcal O(n\log n) ,感谢“排序”送出的一个瓶颈。

代码

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}

const int MaxN = 300005;
int n, a[MaxN];
struct Node{
	int i, j, d;
	Node(int I=0,int J=0,int D=0){
		i = I, j = J, d = D;
	}
	bool operator < (const Node &that) const {
		return i < that.i;
	}
};
vector< Node > ans;
Node ori[MaxN];

int main(){
	n = readint();
	for(int i=1; i<=n; ++i){
		ori[i].i = readint();
		ori[i].j = i;
	}
	for(int i=1; i<=n; ++i)
		a[i] = readint();
	sort(ori+1,ori+n+1);
	sort(a+1,a+n+1);
	for(int i=1; i<=n; ++i)
		a[i] = ori[i].i-a[i];
	a[n+1] = -1;
	for(int i=1,j=1; i<=n; ++i){
		while(a[i] > 0){
			for(; !a[j]; ++j);
			if(j >= i){
				puts("NO"); return 0;
			}
			int d = min(a[i],-a[j]);
			ans.push_back(Node(j,i,d));
			a[j] += d, a[i] -= d;
		}
		if(a[i] > 0){
			puts("NO"); return 0;
		}
	}
	for(int i=1; i<=n; ++i)
		if(a[i] != 0){
			puts("NO"); return 0;
		}
	puts("YES"); int len = ans.size();
	printf("%d\n",len);
	for(int i=0; i<len; ++i){
		printf("%d ",ori[ans[i].i].j);
		printf("%d ",ori[ans[i].j].j);
		printf("%d\n",ans[i].d);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42101694/article/details/107949026
今日推荐