题目
思路
我们显然可以规定变化量 d = 1 d=1 d=1 ,但是多次操作。
当第 i i i 小的元素增大到与第 i + 1 i+1 i+1 小的元素一样大时,如果我们继续增大第 i i i 小的元素,完全可以改成增大第 i + 1 i+1 i+1 小的元素。这与增大第 i i i 小的元素的效果相同。
所以我们得出结论,数字之间大小关系可以不发生改变。
既然如此, s , t s,t s,t 都可以排序。再给出以下结论:如果 s i > t i s_i>t_i si>ti ,则 一定可以 也 必须 往前分摊。若无法分摊,则无解。这完全是“大小关系不改变”的推论。
代码实现很简单了,用 p p p 存储最远的一个“坑”( s i < t i s_i<t_i si<ti 的地方)。显然,一次操作要么填满一个“坑”,要么让当前多出的部分全部消失,所以最多操作 n n n 次。而 p p p 的总移动复杂度也才 O ( n ) \mathcal O(n) O(n) 。
最终时间复杂度为 O ( n log n ) \mathcal O(n\log n) O(nlogn) ,感谢“排序”送出的一个瓶颈。
代码
#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;
}