cfRound932div2-CD题解

C-Messenger in MAC

题意:

即输入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更大,剩下可选的空间更小,就算边界真的pop了,边界成为了b(r-x1)-b(l+x2)。这个不合法的不会成为答案,因为后面肯定会遍历到b(r-x1)-b(l+x2),此时这个差值应该会更小。那么可选的空间更大,更可能更新答案。

""如果弹出的是中间的值,那么就无所谓,反正本来所选的部分就不用连续,但是如果弹出了左右边界,那么我们维护的br-bl岂不是失效了,假设我们真的弹出了左右边界,那么当前的左边界应该是l+c,右边界应该是r-d,这个区间我们在设定左边界为l+c的时候会遍历到,而且因为区间缩小了,左右边界更近了,所以实际的br-bl可能会变小,这里用一个更大的值来表示,不会多算,但是却可以帮我们访问所有的情况。显然区间固定的时候,弹出较大的a是可行的策略。""--csdn-as_sun的题解

""ps:这题很巧妙,很明显是有冗余的,而且一些特殊情况会影响我们表达式的正确性,但是冗余的影响实际上是不会干扰结果的。""--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

题意:

做法:见代码注释。

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

 

posted @ 2024-03-13 01:03  osir  阅读(3)  评论(0编辑  收藏  举报