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