test20181015 B君的第二题
题意
分析
考场85分
用multiset暴力,由于教练的机子飞快,有写priority_queue水过了的人。
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;
const int MAXN=1e5+7;
int p[MAXN];
struct node
{
double pri;
int id,num;
node(double pri=0,int id=0,int num=0):pri(pri),id(id),num(num){}
bool operator<(const node&rhs)const
{
return pri > rhs.pri || (pri == rhs.pri && id < rhs.id);
}
};
multiset<node>H;
multiset<node>::iterator it;
int cnt[MAXN];
int main()
{
freopen("taiyuan.in","r",stdin);
freopen("taiyuan.out","w",stdout);
int n,m;
read(n);read(m);
for(int i=1;i<=n;++i)
{
read(p[i]);
H.insert(node(p[i],i,1));
}
node t;
for(int i=1;i<=m;++i)
{
it=H.begin();
t=*it;
H.erase(it);
++cnt[t.id];
t.pri=(double)p[t.id]/(++t.num);
H.insert(t);
}
for(int i=1;i<=n;++i)
{
printf("%d\n",cnt[i]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
标解
对于满分来说,关键在于直接算。
那么如果不考虑精度问题,我们可以直接实数二分当选的票数,计算出有多少人当选,最后处理一下票数相同的情况。很遗憾这个方法的精度几乎一定会爆炸。
最终的解法大概是,对于票数最多的党,整数二分这个党当选了多少人。
用这个人数最多的党,去推别的党当选了多少人。
这样推出来的结果,最多差1。
最后贪心下。
标程中的⽅法是直接虚拟一个党有10000 票,然后开始二分。
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x)
{
T data=0;
int w=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(isdigit(ch))
data=10*data+ch-'0',ch=getchar();
return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;
const int MAXN=1e5+7;
int n,m;
int p[MAXN];
int z[MAXN];
const int Q=1e4;
ll calc(ll t)
{
ll res=0;
for(int i=0;i<n;++i)
{
res+=p[i]*t/Q;
res=min(res,(ll)1e18);
}
return res;
}
struct node
{
int x,y;
int id;
node()=default;
node(int x,int y,int id):x(x),y(y),id(id){}
bool operator<(const node&rhs)const
{
if((ll)x*rhs.y!=(ll)y*rhs.x)
{
return (ll)x*rhs.y>(ll)y*rhs.x;
}
return id<rhs.id;
}
};
int main()
{
freopen("taiyuan.in","r",stdin);
freopen("taiyuan.out","w",stdout);
read(n);read(m);
for(int i=0;i<n;++i)
{
read(p[i]);
}
ll L=0,R=1e13;
while(L<R-1)
{
ll M=(L+R)/2;
if(calc(M)<=m)
L=M;
else
R=M;
}
int t=m-calc(L);
vector<node>V;
for(int i=0;i<n;++i)
{
z[i]=p[i]*L/Q;
if(p[i]*L/Q!=p[i]*R/Q)
{
V.push_back(node(p[i],z[i]+1,i));
}
}
sort(V.begin(),V.end());
for(int i=0;i<t;++i)
{
++z[V[i].id];
}
for(int i=0;i<n;++i)
{
printf("%d\n",z[i]);
}
// fclose(stdin);
// fclose(stdout);
return 0;
}
解释一下,由于实数二分的精度问题,我们假设二分的实数为\(\frac{Q}{t}\),那么当选人数为:
\[\sum_{i} p_i / \frac{Q}{t}
= \sum_{i} p_i * t / Q
\]
然后改为二分这个\(t\)。
静渊以有谋,疏通而知事。