cf963

A. Question Marks(贪心)

题意:给了4n个问题,每个问题有四个选项ABCD,每个答案有n个问题,如果他不会他就写问号,求最多能答对几题

分析:每次加上选项的次数与n的最小值即可。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void sol(){
    ll n;cin>>n;
    string s;cin>>s;
    map<char,ll>mp;
    for(int i=0;i<4*n;i++){
        mp[s[i]]++;
    }
    ll ans=0;
    for(auto &x:mp){
        if(x.first!='?')
        ans+=min(x.second,n);
    }
    cout<<ans<<endl;
}
int main(){
    int t;cin>>t;
    while(t--)sol();
    return 0;
}

B. Parity and Sum(构造)

题意:给定一个数组a,任选一对牵引i,j,使得ai和aj具有不同的奇偶性,如果ai<aj,ai=ai+aj,否则aj=ai+aj。求使数组中所有元素具有相同奇偶性的最少操作数。

分析:算出最大奇数x,每次比他小的偶数每次更新x,如果x比最大的数小,需要再将x再加上最大的数。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=2e5+10;
ll a[N];
void sol(){
    int n;cin>>n;
    int ji=0,ou=0;
    ll x=0,sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        if(a[i]%2!=0){
            ji++;
            x=max(x,a[i]);
        }
        else ou++;
    }
    sort(a+1,a+1+n);
    if(ji==0||ou==0){
        cout<<0<<endl;
        return;
    }
    else{
        int i=1;
        while(a[i]<=x&&i<=n){
                if(a[i]%2==0){
                    x+=a[i];
                }else{
                    i++;
                    continue;
                }
                i++;
        }
        if(x<a[n])cout<<ou+1<<endl;
        else cout<<ou<<endl;
    }   
}
int main(){
    int t; cin>>t;
    while(t--)sol();
    return 0;
}

C. Light Switches(数学)

题意:房间的灯起初都是关闭,安装芯片后,它先开灯k分钟,再关灯k分钟,重复,最早什么时候这些灯全部打开

分析:由于灯是周期性,可以对2k取模,得到余数b,只要余数最大差值小于k即可,此时就知道每个点的开始和结束(结束就是开始加k),然后求出所有交点的最小值加上k的倍数大于等于a数组的最大值即可。特殊:样例7余数是01289,可以将0变成10,1变成11,2变成12,这样差值就不会大于k了。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=2e5+10;
ll a[N],b[N];
void sol(){
    int n,k;cin>>n>>k;
    for(int i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+n+1);
    ll mi=0x3f3f3f,ma=0;
    ll c=0;//为了后面操作增几倍2k准备
    for(int i=1;i<=n;i++){
        b[i]=a[i]%(2*k);
        c=max(a[i]/(2*k),c);
    }
    sort(b+1,b+n+1);
    for(int i=1;i<=n;i++){
        if(b[i]+2*k-b[n]<=b[n]-b[i]){
            b[i]+=2*k;
        }
        ma=max(ma,b[i]);
        mi=min(mi,b[i]);
    }
    int l=ma,r=mi+k-1;
    if(ma-mi>=k||(l>r)){
        cout<<"-1"<<endl;
        return;
    }
    ll ans=min(l,r);
    if(ans>=a[n]){
        cout<<ans<<endl;
        return;
    }
    ll sum=0;
    while(sum<a[n]){//只要让答案不小于an即可
        sum=ans+(c-1)*(k*2);
        c++;
    }
    cout<<sum<<endl;
}
int main(){
    int t; cin>>t;
    while(t--)sol();
    return 0;
}

D. Med-imize(二分+dp)

题意:给定n和k以及数组a,任意选长度为k的子数组删掉,如果数组的长度还是大于k必须重复操作。求剩余元素最大中值为多少

分析:先算出剩余元素有sz个,用二分找到符合条件的最大值。例如k=3,数组下标总是呈现012012012,删除任意三个数字呈现012012,一直呈现周期性,这时候用dp记录大于x(我们要找的值)的个数,如果有一半的数字大于x则返回true

代码:

#include <bits/stdc++.h>
using namespace std;
void solve(){
    int n,k;cin>>n>>k;
    vector<int>a(n);
    for(int i=0;i<n;i++)cin>>a[i];
    int sz=n%k;
    if(!sz)sz+=k;
    auto check=[&](int x){
        vector<int>dp(sz,0);//存储的是>=x的个数
        for(int i=0;i<n;i++){
            int j=i%k;
            if(j>=sz)continue;
            if(!j)dp[j]=max(dp[j],(int)(a[i]>=x));
            else dp[j]=max(dp[j],dp[j-1]+(a[i]>=x));
        }
        return 2*dp[sz-1]>sz;
    };
    int l=1,r=1e9;
    while(l<=r){
        int mid=l+r>>1;
        if(check(mid))l=mid+1;
        else r=mid-1;
    }
    cout<<r<<endl;
}    
int main(void){
    cin.tie(0)->sync_with_stdio(0);
    int t;cin>>t;
    while(t--)
    solve();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值