题目:点击打开链接
题意:有n台电脑,m个插座,每台电脑的功率是p_i,每个插座哦的功率是s_i,只有当p_i=s_i时,电脑和插座才能连起来。有种变压器,能将插座的功率减半并向上取整,并且变压器能连接使用,求最多能有几台电脑连接上插座,当台数最多时,取变压器最少的情况,输出连接成功的电脑个数,变压器使用个数,每个插座使用变压器的数目,每台电脑连到哪个插座,若不连接输出零。
分析:对于同一台电脑,如果有多个插座接上不相同的变压器都能连接,要取s_i最小的那个插座,因为大的插座可能还可以满足于其他电脑,且使用的变压器数目少,所以要从插座s_i小的开始枚举,看是否有没有满足功率相同的电脑,满足则保存答案,若不能满足则插座功率每次都除以二取上界,直到功率为一以后还不满足则循环,枚举下一个插座,直到枚举完所有的插座。我们可以用STL中的multiset记录每台电脑的功率,multimap记录每种功率对应的电脑编号,插座功率与电脑功率相同时,将记录从multiset和multimap中删除,注意各STL函数的返回值,set的find函数返回迭代器,count函数返回数目,multimap是用pair储存的。
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = (1ULL<<63)-1;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=200010;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
PR com[N],soc[N];
multiset<int> s;
multiset<int>::iterator sit,spos;
multimap<int,int> mp;
multimap<int,int>::iterator mit,mpos;
int n,m,u,c;
int a[N],b[N];
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
scanf("%d",&com[i].fi);
com[i].se=i;
s.insert(com[i].fi);
mp.insert(MP(com[i].fi,i));
}
for(i=1;i<=m;i++)
{
scanf("%d",&soc[i].fi);
soc[i].se=i;
}
sort(soc+1,soc+1+m);
for(i=1;i<=m;i++)
{
int sum=0;
while(1)
{
spos=s.find(soc[i].fi);
if(spos!=s.end())
{
mpos=mp.find(soc[i].fi);
a[soc[i].se]=sum;
b[(*mpos).se]=soc[i].se;
c++;
u+=sum;
s.erase(spos);
mp.erase(mpos);
break;
}
if(soc[i].fi==1) break;
sum++;
soc[i].fi=(soc[i].fi+1)/2;
}
}
printf("%d %d\n",c,u);
for(i=1;i<=m;i++)printf("%d ",a[i]);puts("");
for(i=1;i<=n;i++)printf("%d ",b[i]);puts("");
}