\(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\n",ans);
for(LL i=1;i<=ans;i++)
printf("%lld ",c[i].id);
return 0;
}