cfRound932div2-CD題解

ouhq發表於2024-03-13

C-Messenger in MAC

題意:cfRound932div2-CD題解cfRound932div2-CD題解

即輸入n個pair<int,int> [a,b],任意選擇0個或多個arri,使得式子值小於等於K的情況下,最多可以選幾個不同的i。i可以不連續.可以只選一個點,但不可以重複選一個點。

做法:思維。可以發現按b從小到大排序之後,b部分計算的值為br-bl.因此可以按照b從小到大排序,列舉l,r。o(n*n),4e6.

因為確定了l,r那麼l,r之間的 i 無論怎麼選,b的值都不會改變。此時只需要考慮a的值。需要用的是大根堆,存放每次固定l時,從l到r的所有a的值,一旦a太大,直接pop,

因為後面的br-bl(bl固定,br增大)會更大。此時不滿足,後面更加不會滿足。

??疑惑的關鍵點:

""如果彈出的是中間的值,那麼就無所謂,反正本來所選的部分就不用連續,但是如果彈出了左右邊界,那麼我們維護的br-bl豈不是失效了,假設我們真的彈出了左右邊界,那麼當前的左邊界應該是l+c,右邊界應該是r-d,這個區間我們在設定左邊界為l+c的時候會遍歷到,而且因為區間縮小了,左右邊界更近了,所以實際的br-bl可能會變小,這裡用一個更大的值來表示,不會多算,但是卻可以幫我們訪問所有的情況。顯然區間固定的時候,彈出較大的a是可行的策略。""--csdn-as_sun的題解

#include<bits/stdc++.h>
using namespace std;
#define int long long

bool cmp(pair<int,int> a,pair<int,int> b){
	return a.second<b.second;
}
void solve(){
	int n,k,ans=0;
	cin>>n>>k;
	pair<int,int> arr[2003];
	for(int i=1;i<=n;i++) cin>>arr[i].first>>arr[i].second;
	sort(arr+1,arr+n+1,cmp);
	for(int i=1;i<=n;i++){    									//7 8 17 22 28 
		//priority_queue<int,vector<int>,greater<int> > pq;   //greater是小根堆 
		priority_queue<int> pq;   //預設是大根堆 
		int sum=0,last=0;
		for(int j=i;j<=n;j++){
			sum-=last;        //減去上一組的br-bl的值
			sum+=arr[j].second-arr[i].second;
			last=arr[j].second-arr[i].second;   
			pq.push(arr[j].first);	
			sum+=arr[j].first;
//				priority_queue<int,vector<int>,greater<int> > pq0=pq;      //因為b是從小到大排序,所以如果前面的pq.top()已經太大了,後面肯定更加用不上,可以直接pop() 
			while(pq.size()&&sum>k){
				sum-=pq.top();
				pq.pop();
			}
			ans=max(ans,(int)pq.size());
		}
	}
	cout<<ans<<"\n"; 
}

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	int t=1;
	cin>>t;
	while(t--){
		solve();
	}
	return 0;
}

D-Exam in MAC

題意:cfRound932div2-CD題解cfRound932div2-CD題解

cfRound932div2-CD題解

做法:見程式碼註釋。

void solve(){       //容斥,正難則反
    //合法的pair有很多,那麼我們可以反正做.直接算出所有組合的ans,再減去不合法的組合(y+x)的個數和(y-x)的個數.
    //但是這樣是多減了一部分,那麼ans需要加上同時滿足(y+x)不合法且(y-x)也不合法的個數.
    //y+x和y-x不合法的個數容易計算,但是同時不合法的應該怎麼計算?
    //設y+x=ai;
    // y-x=aj;
    //那麼有:x=(ai-aj)/2;
    //      y=(ai+aj)/2;
    //因為選擇組成pair的值都是整數,那麼(ai-aj)和(ai+aj)都必須是2的倍數,且ai>=aj!!;
    //即ai,aj同奇或同偶;
    //那麼只需要數出輸入的數之中odd的個數和even的個數,然後進行兩兩組合即可(ai>=aj).
    //不用擔心組合會不會是不存在的,因為所選的ai和aj都是來自輸入的數字,並且是同奇偶的.那麼總是有組合x,y是可以同時滿足y+x=ai,y-x=aj.
    int n,c,arr[300005],ans=0;
    cin>>n>>c;
    ans=(c+1)*(1+c+1)/2;
    int cntodd=0,cnteven=0;
    for(int i=1;i<=n;i++) {
        cin>>arr[i];
        if(arr[i]&1) cntodd++;
        else cnteven++;
        ans-=(arr[i]/2)+1;   //y+x
        ans-=c-arr[i]+1;               //y-x
    }
    ans+=cntodd*(cntodd+1)/2;
    ans+=cnteven*(cnteven+1)/2;
    cout<<ans<<endl;
}