CF1416B Make Them Equal

首先观察到每次操作不会改变整个数组的和 sum,所以最终整个数组都会变成平均数

因此如果sum不是n的倍数 则无解

由于没观察到这个点导致我被卡的死死的

其次就是当选择(1, i, x)这个三元组的时候,可以对任意的 x>=a[1],a[1]-=x,a[i]+=x, 这就使每次加减的数不受是"某个除1以外的数的倍数"的限制

所以接下来的想法是把a[2]~a[n]都加到a[1]上,然后再由a[1]分配到这些位置上

由于a[i]只能减去i的倍数的数所以可分为两种情况

1.a[i]是i的倍数

2.a[i]不是i的倍数

对于情况1 可以直接把a[i]加到a[1]上,记为1次操作

而对于情况2 则需要从a[1]“借”来一些数,让a[i]变为i的倍数

具体操作为: a[1]-=i-a[i]%i a[i]+=i-a[i]%i,然后当情况1处理,这就记为2次操作

在这里可以看到a[1]有变为负数的可能,其实可以证明a[1]在操作过程中始终不为负数,证明如下:

当处理到a[i]时 此时a[1]等于前i-1项的和,因为数组的数大于等于1,则a[1]>=i-1,而i-a[i]%i<=i-1,所以a[1]始终>=0

最后“a[2]~a[n]都加到a[1]上”这个操作最多有2*(n-1)次,a[1]进行分配需要操作n-1次,总操作数不超过3*(n-1)次 符合题目要求

 

 

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define db double
#define rep(x,a,b) for(int x=(a);x<=(b);x++)
#define per(x,a,b) for(int x=(a);x>=(b);x--)
#define scf(a) scanf("%d",&a)
#define scfll(a) scanf("%lld",&a)
#define scfdb(a) scanf("%lf",&a)
#define ptf(a) printf("%d",a)
#define ptfll(a) printf("%lld",a)
#define ptfdb(x,a) printf("%x.lf",a)
#define ptfsp(a) printf("%d ",a)
#define ptfllsp(a) printf("%lld ",a)
#define ptfdbsp(x,a) printf("%x.lf ",a)
#define pli(a,b) make_pair(a,b)
#define pb push_back
#define el puts("")
#define pi 3.1415926
using namespace std;
const int maxn=2e5+5;
const ll mod=1e9+7;
struct node{
    int i,j,val;
}ans[maxn];
int a[maxn];
int main(){
    int T;scf(T);
    while(T--){
        int n;scf(n);
        int sum=0;
        rep(i,1,n) scf(a[i]),sum+=a[i];
        if(sum%n!=0){
            puts("-1");
            continue;
        }
        int cnt=0;
        rep(i,2,n){
            if(a[i]%i){
                ans[++cnt]=(node){1,i,i-a[i]%i};
                a[1]-=i-a[i]%i;
                a[i]+=i-a[i]%i;
            }
            ans[++cnt]=(node){i,1,a[i]/i};
            a[1]+=a[i];
            a[i]=0;
        }
        rep(i,2,n)
            ans[++cnt]=(node){1,i,sum/n};
        ptf(cnt);el;
        rep(i,1,cnt)
            ptfsp(ans[i].i),ptfsp(ans[i].j),ptfsp(ans[i].val),el;
    }
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值