ZR贪心10.2

(shop)

题目链接

比较容易想到的是先进行赋值操作,并且每个位置只赋值一次。加法操作肯定是选前几次大的。
如果是同一种操作的话,只要排个序就行,但是有三种操作怎么办呢?
我们可以把它转化成同一种操作。
具体实现:
先把赋值转化成加法操作(加上差值),再把加法操作们转化成乘法操作。
重点来了:
不能直接把赋值操作转化成乘法操作。因为加法操作变成乘法操作时,要用到加之前的值。我们默认从大到小加...
举个例子吧:
有个数3,答案是先把它变成5,再加6。
变成5是乘(frac{5}{3}),加2是乘(frac{13}{5})
但是如果直接把赋值变成乘的话,就变成乘(frac{5}{3}),乘(frac{9}{3})
竟然还能过146个点
还有就是一个小错点,因为把赋值变成了加操作,所以(vector)里存的不全是加法操作了(还有(flag)为1的情况)

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#define LL long long
using namespace std;
const LL N = 100005;
LL n,m,a[N],tot,ans,k;
struct node{
	LL p,data,flag;
}opt[N];
vector<node> v[N];
struct Node{
	LL id,flag;
	double val;
}c[N];
bool cmp(const node &x,const node &y)
{ return x.data>y.data; }
bool cmp1(const Node &x,const Node &y)
{ return x.val>y.val; }
bool cmp2(const Node &x,const Node &y)
{ return x.flag<y.flag; }
int main()
{
	scanf("%lld%lld%lld",&k,&n,&m);
	for(LL i=1;i<=k;i++)
	 scanf("%lld",&a[i]);
	LL x,y,z;
	for(LL i=1;i<=n;i++)
	{
		scanf("%lld%lld%lld",&x,&y,&z);
		if(x==1&&z>a[y])
		{
			if(opt[y].data<z)
			{
				opt[y].data=z;
				opt[y].p=i;
				opt[y].flag=x;
			}
		}
		if(x==2&&z>0)
		 v[y].push_back((node){i,z,2});
		if(x==3&&z>1)
		{
			c[++tot].id=i;
			c[tot].val=(double)z;
			c[tot].flag=3;
		}
	}
	for(LL i=1;i<=k;i++)
	{
		if(opt[i].data>0)
		{
			v[i].push_back((node){opt[i].p,opt[i].data-a[i],1});
			/*c[++tot].id=opt[i].p;
			c[tot].flag=opt[i].flag;
			c[tot].val=double(opt[i].data)/a[i];*/
		}
		sort(v[i].begin(),v[i].end(),cmp);
		for(LL j=0;j<v[i].size();j++)
		{
			node tmp=v[i][j];
			c[++tot].id=tmp.p;
			c[tot].flag=tmp.flag;
			c[tot].val=(double(a[i]+tmp.data)/a[i]);
			a[i]+=tmp.data;
		}
	}
	sort(c+1,c+tot+1,cmp1);
	ans=min(m,tot);
	sort(c+1,c+ans+1,cmp2);
	printf("%lld
",ans);
	for(LL i=1;i<=ans;i++)
	 printf("%lld ",c[i].id);
	return 0;
}
原文地址:https://www.cnblogs.com/karryW/p/11635895.html