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\)

posted on 2018-10-16 08:06  autoint  阅读(201)  评论(0编辑  收藏  举报

导航