1. 程式人生 > >CF-517C-思維/math

CF-517C-思維/math

print tdi 我們 space printf -- ... 一次 個數

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 }

CF-517C-思維/math