Julyc和CerberuX去吃饭后传
发布时间: 2017年6月18日 21:39 最后更新: 2017年6月18日 21:43 时间限制: 1000ms 内存限制: 128M SPJ
上次Julyc和CerberuX因为去吃饭打的不可开交,而一般人都不会想和CerberuX打架,Julyc也不例外。这次他们去了一条小吃街,小吃街里有n种小吃,Julyc和CerberuX口味不同,对于每一种小吃,每个人都有着各自的对这种小吃的喜爱值,虽然Julyc非常想独自行动,但是每次独自行动后CerberuX都会走丢(即使学校门口的小吃街),所以Julyc和CerberuX必须一起行动,也就是说他们要选择相同的小吃。先约定一个人“吃得好”是指他吃到的小吃的喜爱值(他对这种小吃的喜爱值)累加之和大于没吃到的那些小吃的喜爱值(他对这种小吃的喜爱值)之和。然而他们的饭量有限,并且也不想吃的太少,所以他们必然会吃(n/2)+1(注意是整除)种小吃(每种小吃的份量是相同的,所以不考虑份量问题)。为了不使他俩打起来,必须要让他俩都“吃得好”,现在给你n,给你每个人分别对这n种小吃的喜爱值,请你帮助他们选择(n/2)+1(注意是整除)种合适的小吃,使得Julyc和CerberuX都可以“吃的好”。
第一行输入测试用例的个数T(0<T<=10)。
对于每一个测试用例输入三行,第一行一个正整数n(1<=n<=1e5)代表有n种小吃。
第二行输入n个正整数a1...an(1<=ai<=1e9),ai代表Julyc对第i种小吃的喜爱值。
第三行输入n个正整数b1...bn(1<=bi<=1e9),bi代表CerberuX对小吃的喜爱值。
对于每一个测试用例输出两行,第一行一个正整数k,代表选择了k种小吃。
第二行k个正整数c1...ck(1<=ci<=n),代表选择了哪些小吃,并请按照从小到大的顺序输出。(ci指第ci种小吃)
1 5 8 7 4 8 3 4 2 5 3 7
3 1 4 5
1 2 1 2 3 4
2 1 2
思路:
由于必吃n/2+1种,即如果只满足一个人"吃的好"是必定能实现的,就保证了下面的贪心是可行的。首先根据两人的喜爱值排两个序,然后很容易会想到交叉地区构造两个喜爱值的和是可行的,但是何时转移?:哪一方的未得到的喜爱值与总喜爱值的比值较大,则根据有序序列去构造它。
服务器不稳定,T了一发让我以为写一个复杂度较高的函数却不用它会导致超时?否,后来交就过了= =。
代码:
#include <algorithm>
#include <iostream>
#include <string.h>
#include <cstdio>
#define LL long long
using namespace std;
const int maxn = 1e5+5;
// const double eps = 1e-14;
struct node
{
int id, val1, val2;
} a[maxn], b[maxn];
int vis[maxn], ans[maxn];
int cmp1(node x, node y)
{
if(x.val1 == y.val1) return x.val2 > y.val2;
return x.val1 > y.val1;
}
int cmp2(node x, node y)
{
if(x.val2 == y.val2) return x.val1 > y.val1;
return x.val2 > y.val2;
}
/*
double work(LL a, LL b)
{
double mid, l = 0, r = b;
while(r-l >= eps)
{
mid = (r+l)/2;
if(mid*b > a) r = mid;
else l = mid;
}
return l;
}
*/
int jg(LL a1, LL b1, LL a2, LL b2)
{
return (b1-a1)*1.0/b1 > (b2-a2)*1.0/b2;
//return work((b1-a1)*1.0, b1) > work((b2-a2)*1.0, b2);
}
int main()
{
int t, n, cnt;
LL sum1, sum2, now1, now2;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n); cnt = n/2+1;
sum1 = sum2 = 0;
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i].val1);
sum1 += a[i].val1;
b[i].val1 = a[i].val1;
a[i].id = b[i].id = i;
}
for(int i = 1; i <= n; ++i)
{
scanf("%d", &a[i].val2);
sum2 += a[i].val2;
b[i].val2 = a[i].val2;
}
sort(a+1, a+n+1, cmp1);
sort(b+1, b+n+1, cmp2);
now1 = now2 = 0;
memset(vis, 0, sizeof vis);
int i = 1, j = 1;
for(int k = 1; k <= cnt; ++k)
{
if(jg(now1, sum1, now2, sum2))
{
for(; i <= n; ++i)
if(!vis[a[i].id]) break;
vis[a[i].id] = 1;
now1 += a[i].val1;
now2 += a[i].val2;
ans[k] = a[i].id;
++i;
}
else
{
for(; j <= n; ++j)
if(!vis[b[j].id]) break;
vis[b[j].id] = 1;
now1 += b[j].val1;
now2 += b[j].val2;
ans[k] = b[j].id;
++j;
}
}
sort(ans+1, ans+cnt+1);
printf("%d\n", cnt);
for(int i = 1; i <= cnt; ++i)
printf("%d%c", ans[i], i==cnt?'\n':' ');
}
return 0;
}
继续加油~