题意:n个服务器 第i个服务器最多能负载a[i]单元.现在有两个任务其值为s1,s2
若有一个任务值为S,分给k个服务器 则这k个服务器其a[i]值>=(S+k-1)/k
每台服务器最多运行一个任务.问任务s1,s2是否能通过这n个服务器运行起来.
n<=3e5.1<=a[i],s1,s2<=1e9 有解输出方案,两个任务各自要用的服务器,否则输出-1.
枚举任务1要用到x台服务器,那么这x台中最小的为val=(s1+x-1)/x
在a二分找到第一个>=val的下标i,此时显然取[i,i+x-1]是最优的.
现在开始处理s2.
预处理出f[i]表示以i为最小值时,完成s2以后,最多剩下多少个.
那么在枚举完x以后,求出[1,i-1]中是否有f[i]>=x (预处理前缀i中f的最大值),
若有一个任务值为S,分给k个服务器 则这k个服务器其a[i]值>=(S+k-1)/k
每台服务器最多运行一个任务.问任务s1,s2是否能通过这n个服务器运行起来.
n<=3e5.1<=a[i],s1,s2<=1e9 有解输出方案,两个任务各自要用的服务器,否则输出-1.
枚举任务1要用到x台服务器,那么这x台中最小的为val=(s1+x-1)/x
在a二分找到第一个>=val的下标i,此时显然取[i,i+x-1]是最优的.
现在开始处理s2.
预处理出f[i]表示以i为最小值时,完成s2以后,最多剩下多少个.
那么在枚举完x以后,求出[1,i-1]中是否有f[i]>=x (预处理前缀i中f的最大值),
或者后缀[i+x,n]中是否存在j满足:以j为最小值能满足s2.
#include <bits/stdc++.h>
using namespace std;
const int N=6e5+5;
int n,s1,s2,b[N],f[N];
int pre[N][2],suf[N];
struct node{
int x,id;
}a[N];
vector<int> v,v1,v2;
bool cmp(node a,node b)
{
if(a.x==b.x)
return a.id<b.id;
return a.x<b.x;
}
void print(int id,int x,int p)
{
cout<<"Yes"<<'\n';
for(int i=id;i<=id+x-1;i++)
v1.push_back(a[i].id);
for(int i=p,cnt=1;cnt<=(s2+b[p]-1)/b[p];i++)
{
if(i>=id&&i<=id+x-1)
continue;
v2.push_back(a[i].id);
cnt++;
}
cout<<v1.size()<<' '<<v2.size()<<'\n';
for(int i=0;i<v1.size();i++)
cout<<v1[i]<<' ';
cout<<'\n';
for(int i=0;i<v2.size();i++)
cout<<v2[i]<<' ';
cout<<'\n';
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n>>s1>>s2;
for(int i=1;i<=n;i++)
cin>>a[i].x,a[i].id=i;
sort(a+1,a+1+n,cmp);
for(int i=1;i<=n;i++)
{
b[i]=a[i].x;
int k=(s2+a[i].x-1)/a[i].x;
if(k<=n-i+1)
f[i]=n-i+1-k;
else
f[i]=-1;
pre[i][0]=pre[i-1][0];
pre[i][1]=pre[i-1][1];
if(f[i]>pre[i-1][0])
pre[i][0]=f[i],pre[i][1]=i;
}
for(int i=n;i>=1;i--)
{
if(f[i]!=-1)
{
suf[i]=max(suf[i+1],i);
continue;
}
suf[i]=suf[i+1];
}
for(int x=1;x<n;x++)
{
int val=(s1+x-1)/x;
int idx=lower_bound(b+1,b+1+n,val)-(b+1)+1;
if(idx+x-1>n)
continue;
int id=idx+x;
if(suf[id]!=0)
{
print(idx,x,suf[id]);
return 0;
}
if(pre[idx-1][0]>=x)
{
print(idx,x,pre[idx-1][1]);
return 0;
}
}
cout<<"No"<<'\n';
return 0;
}
官方解:
设k1,k2分别为两个任务所用服务器个数. s1<s2
p1=s1/k1,p2=s2/k2 任务1从第一个>=p1的机器开始选k1个.
此时任务2从后缀开始往前取k2个 要满足不能与k1选的重叠 并且这k2个的最小值>=p2.
即任务2的最小值越大越好 也就是无论k1是多少,k2越小越好.
那么直接找到最小的k2,然后在枚举的k1即可.
tourist代码:
/**
* author: tourist
* created: 29.04.2018 16:25:11
**/
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
vector<int> x(2);
cin >> n >> x[0] >> x[1];
vector< pair<int,int> > c(n);
for (int i = 0; i < n; i++) {
cin >> c[i].first;
c[i].second = i;
}
sort(c.rbegin(), c.rend());
for (int rot = 0; rot < 2; rot++) {
int use = -1;
for (int i = 0; i < n; i++) {
if (x[0] <= (long long) c[i].first * (i + 1)) {
use = i + 1;
break;
}
}
if (use != -1) {
int use2 = -1;
for (int i = use; i < n; i++) {
if (x[1] <= (long long) c[i].first * (i - use + 1)) {
use2 = i - use + 1;
break;
}
}
if (use2 != -1) {
cout << "Yes" << '\n';
vector< vector<int> > res(2);
for (int i = 0; i < use; i++) {
res[rot].push_back(c[i].second);
}
for (int i = 0; i < use2; i++) {
res[rot ^ 1].push_back(c[use + i].second);
}
cout << (int) res[0].size() << " " << (int) res[1].size() << '\n';
for (int q = 0; q < 2; q++) {
for (int i = 0; i < (int) res[q].size(); i++) {
if (i > 0) {
cout << ' ';
}
cout << res[q][i] + 1;
}
cout << '\n';
}
return 0;
}
}
swap(x[0], x[1]);
}
cout << "No" << '\n';
return 0;
}