我正在尝试解决Sphere Online Judge's "FOODIES - ChickenLove" problem。在这个问题中,有 n 形式{1,2,..., A1 },{1,2,..., A2 },...,{1,2,..., An }。 (输入只包含整数 A1 , A2 ,... An ;隐含了其他元素。)问题的目标是,对于给定的 m ,通过从这些集合中选择 m 不同的元素来找到可以获得的最大总和。
例如,给定此输入:
期望的结果是4 + 4 + 5 = 13 。
目前我正在使用优先级队列来解决这个问题,但是我遇到了“超时”错误(这意味着我的解决方案需要太长时间)。如何优化我的解决方案?有更好的方法吗?
我当前的方法
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k,x;
long long c=0;
scanf("%d",&n);
priority_queue<int> pq;
for(int i=0;i<n;i++)
{
scanf("%d",&x);
pq.push(x);
}
scanf("%d",&k);
for(int i=1;i<=k;i++)
{
int p=pq.top();
c+=p;
pq.push(p-1);
pq.pop();
}
printf("%lld\n",c);
}
return 0;
}
答案 0 :(得分:1)
您的时间限制已超出,因为最大M <= 10^10
,您的代码的时间复杂度为O(N + M log N)
。
这个问题的约束是1 <= A[i] <= 100000
,所以你可以计算所有集合中x的数量(在我的代码中:值为c [x])。
因此,您只需处理1 <= i <= N
的查询。 (c [i]的初始值= 0)
您可以使用O(M)
的幼稚算法和O(N)
的累加和算法进行处理。
如果算上c[1], c[2], ..., c[max(A[1], A[2],..., A[N])]
,就可以像我的代码一样:
#include <bits/stdc++.h>
using namespace std;
int T, N; long long M;
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &N);
vector<int> A(N);
for(int i = 0; i < N; i++) scanf("%d", &A[i]);
scanf("%lld", &M);
int z = *max_element(A.begin(), A.end());
vector<int> c(z + 2), s(z + 2);
for(int i = 0; i < N; i++) s[1]++, s[A[i] + 1]--;
for(int i = 1; i <= z; i++) c[i] = c[i - 1] + s[i];
long long ret = 0;
for(int i = z; i >= 1; i--) {
if(M <= c[i]) {
ret += 1LL * M * i; M = 0;
break;
}
ret += 1LL * c[i] * i; M -= c[i];
}
printf("%lld\n", ret);
}
return 0;
}
整体时间复杂度为O(N + max(A[1], A[2],..., A[N]))
我提交给SPOJ,我得到了AC(0.20秒)!