C. Cram Time
题意
给你两个数a,b,用a,b分别构造两个序列A,B,
要求A序列的和小于a,B序列的和小于b
而且A序列中和B序列中每个数最多在两个序列中出现一次
要是最终的两个序列的长度和最大,输出两个序列
做法
判
断
出
a
+
b
能
够
造
的
的
最
大
的
1
+
2
+
3
+
.
.
.
+
n
判断出a+b能够造的的最大的1+2+3+...+n
判断出a+b能够造的的最大的1+2+3+...+n
如果a+b>=(1+2+3+…n),一定可以构造出(1+2+3+…n)
至于构造方法,就先用a,b中大的数从大到小选,再用小的从大到小选,就OK了!
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5+5;
ll a,b;
vector<int> v1,v2;
int vis[maxn];
int main()
{
scanf("%lld%lld",&a,&b);
ll sum=a+b;
ll pos=0;
for(ll i=0;;i++)
{
if((1LL*i*(i+1))/2==sum)
{
pos=i;
break;
}
else if((1LL*i*(i+1))/2>sum)
{
pos=i-1;
break;
}
}
ll maxx=max(a,b);
ll minn=min(a,b);
ll tmp=sum-(1LL*pos*(pos+1))/2;
for(int i=pos;i>=1;i--)
{
if(maxx>=i)
{
v1.push_back(i);
maxx-=(i);
vis[i]=1;
}
}
for(int i=pos;i>=1;i--)
{
if(vis[i]) continue;
if(minn>=i)
{
v2.push_back(i);
vis[i]=1;
minn-=i;
}
}
if(a>=b)
{
printf("%d\n",v1.size());
for(int i=0;i<v1.size();i++) printf("%d ",v1[i]);
printf("\n%d\n",v2.size());
for(int i=0;i<v2.size();i++) printf("%d ",v2[i]);
}
else
{
printf("%d\n",v2.size());
for(int i=0;i<v2.size();i++) printf("%d ",v2[i]);
printf("\n%d\n",v1.size());
for(int i=0;i<v1.size();i++) printf("%d ",v1[i]);
}
return 0;
}