把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

qzezoj 1568 反复求和

题面传送门
这道题首先要有一个思维的转换:对于选择满足\(0\leq i< n\) 的任意下标\(i\) ,并让\(a\)数组里下标为\(i\)处的值变为\(sum\)。把赋值的思维转化成选择一个下标,把除了这个下标的所有值加到它身上
这道题正着想很难想,俗话说得好,正难则反,所以我们不如倒着做
对于已经构造好的\(a\)序列,首先我们要确定它最后修改的位置。很明显,最后修改的位置是最大的,那么我们要计算它修改前的值,我们的思维转换就要派上用场了,其他值是不变的,所以我们维护一个总值,算出其他值,在这个数上减去就好了,一直到所有数都为\(1\)或有的数\(<1\)为止。
对于找最大值的过程,我们可以用一个大根堆维护。

#include<bits/stdc++.h>
using namespace std;
long long n,m,tot,a[100039],b[100039],sum,ans,pus,sss;
priority_queue<long long,vector<long long>,less<long long> > s;
int main(){
	register int i;
	scanf("%lld",&n);
	for(i=1;i<=n;i++) scanf("%lld",&a[i]),s.push(a[i]),sum+=a[i];
	for(i=1;i<=n;i++) if(a[i]==1) tot++;
	while(tot!=n){
		pus=s.top();
		s.pop();
		ans=sum-pus;
		sum-=ans;
		pus-=ans;
		if(pus==1) tot++;
		else if(pus<1) break;
		else s.push(pus);
	}
	if(tot==n)printf("T");
	else printf("N");
}

但这样有一个问题,有几组\(hack\)数据跑不过去。比如下面这组:

2
1 1000000000

我们发现重复减了很多次,我们可以计算出它要减几次,然后一并减掉。我们把这个元素拿出来,再取出一个堆顶的值,然后将他们两个作差后的结果除以减去的值向下取整再\(+1\),这就是要减的次数,用乘法一并减掉就可以了
AC代码:

#include<bits/stdc++.h>
using namespace std;
long long n,m,tot,a[100039],b[100039],sum,ans,pus,sss,now;
priority_queue<long long,vector<long long>,less<long long> > s;
int main(){
    //freopen("1.in","r",stdin);
    register int i;
    scanf("%lld",&n);
    for(i=1;i<=n;i++) scanf("%lld",&a[i]),sum+=a[i];
    for(i=1;i<=n;i++) if(a[i]==1) tot++;
    else s.push(a[i]);
    //printf("%lld\n",tot);
    while(tot!=n){
        pus=s.top();
        //printf("%lld\n",pus);
        s.pop();
        if(!s.size()){
            if((pus-1)%(n-1)==0) tot=n;
            break; 
        }
        ans=sum-pus;
        now=s.top();
        sum-=((pus-now)/ans+1)*ans;
        pus-=((pus-now)/ans+1)*ans;
        if(pus==1) tot++;
        else if(pus<1) break;
        else s.push(pus);
    }
    if(tot==n)printf("T");
    else printf("N");
}

还有,不开\(long long\)见祖宗啊!!!

posted @ 2020-03-16 13:47  275307894a  阅读(54)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end