1. 程式人生 > 實用技巧 >洛谷 P6851 onu (貪心,模擬)

洛谷 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;
    }