CF-517C-思维/math

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?'
':' ');
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 }
原文地址:https://www.cnblogs.com/zzqc/p/9844270.html