洛谷 P6851 onu (贪心,模拟)

-
题意:C和D打牌,每张牌有花色和点数,小D刚开始的分数为\(v\),不管输还是赢,只要小D出了牌(花色必须相同),就能得到那张牌点数的分数,若是赢了(点数不小于D的牌),他可以另外加\(c\)分,输了就要扣\(c\)分,现在D知道了C的出牌情况,问他最多能拿多少分,并输出出牌情况.
-
题解:首先,假如他两的牌花色不同,那么D一定打不出牌,只能白白\(-=c\),否则我们要尽可能的出多的牌,并且要赢得多,贪心策略是,用D的最大的牌去打掉C最大的牌,如果C同种颜色最小的牌都比D最大的大,那么只能随便打一张骗一点分并且把C的最大的牌消耗掉,实现起来挺复杂的,具体看代码吧.
-
代码:
struct misaka{ int col; int val; int id; bool operator < (const misaka &mikoto) const{ return val<mikoto.val; } bool operator > (const misaka &mikoto) const{ return val>mikoto.val; } }a[N],b[N]; int n,m,c; ll v; multiset<misaka> V[N]; int ans[N]; int main() { ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); cin>>n>>m>>c>>v; for(int i=1;i<=n;++i){ cin>>a[i].col>>a[i].val; a[i].val=-a[i].val; //存负数方便我们后面进行二分查找 a[i].id=i; } for(int i=1;i<=m;++i){ ans[i]=-1; cin>>b[i].col>>b[i].val; b[i].val=-b[i].val; //存负数方便我们后面进行二分查找 b[i].id=i; } sort(a+1,a+1+n); for(int i=1;i<=m;++i){ V[b[i].col].insert(b[i]); //记录小C每种颜色的点数,set会对点数自动排序 } for(int i=1;i<=n;++i){ if(V[a[i].col].empty()) continue; v-=a[i].val; auto p=V[a[i].col].lower_bound(a[i]); //因为全是负数,找小C当前颜色牌中小于小D的牌 if(p==V[a[i].col].end()){ //小D最大的牌打不过小C最小的牌 v-=c; p=V[a[i].col].begin(); //随便出一张 } else v+=c; //auto t=*p; ans[p->id]=a[i].id; //记录ans V[a[i].col].erase(p); //弹出小C的一张牌 } for(int i=1;i<=m;++i){ if(ans[i]==-1) v-=c; } cout<<v<<endl; for(int i=1;i<=m;++i){ cout<<ans[i]<<endl; } return 0; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号