Codeforces Round #517 (Div. 2) C. Cram Time(思维+贪心)

https://codeforces.com/contest/1065

题意

给你a,b,让你找尽量多的自然数,使得他们的和<=a,<=b,用在a和b的自然数不能重复

思路

  • 假如只有一个数a让你去找,问题就很简单了,就是找到一个x,使得x尽量大,且x*(x+1)/2<=a,意味着答案就是1~x
  • 我的思路是从1开始累加,加到一个不能再加的数时,向后退一个数,加上n-sum(1~a[i-1])(ps:a[i+1]为不能再加的数)

错误贪心思想:假如加到不能再加,同样是只能再加一个数了,不如把小的数留给后面

  • 然后就一直wa

  • 正确思路

  • 贪心策略有问题,因为留给第一个数的不一定是[1,2...5,6,100]这样两段数,有可能根据a,b的大小,第一个数也有可能是三段,四段。。。

  • 设c=a+b,那么统一起来考虑,那么组成a和b的数一定为[1~x],其中(1+x)*x/2<=c,且x最大,

  • 那么让x1<=a,且x1尽量大,因此找出x后,从大到小扫,确保能把a尽可能填满,那么剩下数的和一定<=b

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
using namespace std;
ll a,b,sum,i;
vector<ll>A,B;
int main(){
    cin>>a>>b;
    sum=a+b;
    for(i=1;;i++){
        if(i*(i+1)/2>sum)break;
    }i--;
    for(;i>0;i--){
        if(a>=i){
            A.pb(i);a-=i;
        }else B.pb(i);
    }
    cout<<A.size()<<endl;
    for(i=0;i<A.size();i++)printf("%lld ",A[i]);cout<<endl;
    cout<<B.size()<<endl;
    for(i=0;i<B.size();i++)printf("%lld ",B[i]);cout<<endl;
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/9928651.html