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;
}