题意: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; }