http://codeforces.com/contest/1072/problem/C
题目大意是给出两个数a,b ,找出若干个数p,使得 SUM{p}<=a ,找出若干个数q使得SUM{q}<=b ,还要保证找到的p和q都是不一样的数,问|p|+|q|最大是多少。也就是要使得找的数尽可能的多。
如果不是分成两个数a,b的话其实很简单,答案就是 1,2,3.....x ,x是使得(x*(x+1)) <= n成立的最大值。如果拆成两个数,那么这个最大值显然不会比n大。如果能看出这点来就好了,这样我们把
数据范围变成了sqrt(MAXA+MAXB)了。先找到这个x,其实答案就是x ,下面证明下。
已知的是x*(x+1)/2<=n=a+b (1)有一个有趣的知识是用[1,n]内的数每个数最多使用一次,一定能组成[1,(1+n)*n/2]的所有数,首先能组成[1,n],然后把n提出来与前面所有的数依次累加得到[n+1,2n-1],然后把最后两个数提出来与前面的数依次累加得到[2n,3n-3]......由于n=a+b,所以a要么是大于 x*(x+1)/2,这样的话答案就是x,要么a<=x*(x+1)/2,那么a肯定能用一部分数完全组成,那么剩下的数的和就是 x*(x+1)/2-a <=b (由(1)得到) ,所以b一定能装下所有的剩下的数。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 #define LL long long 7 LL x,s,a,b; 8 bool vis[100000]; 9 void f(int n){ 10 vector<int>g; 11 for(int i=x;i>=1;--i){ 12 if(!vis[i]&&i<=n){ 13 vis[i]=1; 14 n-=i; 15 g.push_back(i); 16 } 17 } 18 cout<<g.size()<<endl; 19 for(int i=0;i<g.size();++i) printf("%d%c",g[i],i==g.size()-1?'\n':' '); 20 } 21 int main(){ 22 cin>>a>>b; 23 s=a+b; 24 LL l=0,r=100000; 25 while(l<r){ 26 LL mid=r-(r-l)/2; 27 if(mid*(mid+1)<=s*2){ 28 l=mid; 29 } 30 else{ 31 r=mid-1; 32 } 33 } 34 x=l; 35 f(a),f(b); 36 return 0; 37 }