cf #768 Div.2

cf #768 Div.2

A. Min Max Swap

  • 题意

​ 两个数组a,b,对于同一下标i可以交换a[i],b[i]的值,求max(a)*max(b)最小值

  • 题解

    题目就是要通过某些操作让两个数组中的最值m1*m2乘积最小,首先,所有数的最大值一定是一个数组的最大值死,即m1已经固定,所以需要通过操作使得另一个数组中的最大值m2最小,我们让m1在a中,那么只需把所有a[i]<b[i]的下标都交换,就可以在最大可能下使得b中m2最小,即使得答案最小。

  • 代码

#include <iostream>

using namespace std;
const int N=110;

int n;
int a[N],b[N];

int main(){
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=0;i<n;i++) cin>>a[i];
        for(int i=0;i<n;i++) cin>>b[i];
        
        for(int i=0;i<n;i++)
            if(a[i]<b[i]) swap(a[i],b[i]);//把最大值组置为a数组
        
        int m1=0,m2=0;
        for(int i=0;i<n;i++) {//找m1,m2
            m1=max(m1,a[i]);
            m2=max(m2,b[i]);
        }
        
        cout<<m1*m2<<'\n';
    }
    
    return 0;
}

B. Fun with Even Subarrays

  • 题意

    给定一个整数数组a下标从1开始,可以进行这样的操作:随便选l,k,把a[l,l+k)替换成a[l+k,l+k+k),问最少经过几次这样的操作可以让a中所有数都相等。

  • 题解

    由于题意是把前一个区间段替换成后一个区间段,为了能够尽可能少的次数变成一样的,那么就要求后一个区间段必须已经完全相等。所以从边界开始,最右端的最后一个完全相等的的区间把前一个区间替换,接着把这两个区间看成一整个区间,再把合成区间的前一个区间替换,如此继续直到达到最左端。

    Eg:

    原数组: 4 2 1 3(第一个区间长度为1,数值为3,被替换的数字为1)

    替换后: 4 2 3 3(第二个区间长度为2,数值为33, 被替换的数字为42)

    替换后: 3 3 3 3(第三个区间长度为4,数值为3333,成功操作 )

  • 代码

#include <iostream>

using namespace std;
const int N=2e5+5;

int n;
int a[N];

int solve(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];

    int cnt=0,len=1;//记录次数、已经相等的最大区间长度
    for(int i=n;i>0;i--){//从后往前依次最大限度替换
        if(a[n]==a[i-1] && i-1) len++;//如果和最后一个数相等则区间长度++
        if(a[n]!=a[i-1] && i-1) {//不等则替换,注意不能越界
            cnt++;//替换次数++
            i-=len;i++;//下一区间的尾部的指针更新
            len*=2;//长度增倍
        }
    }

    return cnt;
}

int main() {
    int T;
    cin>>T;
    while(T--)
        cout<<solve()<<'\n';

    return 0;
}

C. And Matching

  • 题意

    给定一个2的幂n[4,2^16],一个整数k[0,n),同时包含0~n-1这些数,把这些数两两a,b一组分为n/2组,输出使得以下式子成立的分组方式
    ∑ i n / 2 a i & b i = k \sum^{n/2}_{i}a_i\& b_i=k in/2ai&bi=k

  • 题解

    以数字8为例

​ 由以上规律可以得到一个一定可以构造出符合式子的分组:其他组别全部取为0,剩下0,n-1,k,Ck(表示与k做&为0的数)四个数,分成(0,Ck)=0,(n-1,k)=k,这样所有的和为k。当然这是在k<n-1的情况下才能剩下这四个数。因此分类讨论:

k<n-1 :按如上方法构造即可

k=n-1 :也有构造方法,其他组全取0,剩下0,1,2,n-3,n-2,n-1用来构成k

​ (n-1)&(n-2)=(n-2) , (n-3)&1=1 , 0&2=0 —>n-1=k

​ 当然,当n=4时没办法给出6个数,所以不能构造成功

  • 代码
#include <iostream>

using namespace std;
const int N=1e6+5;

int T,n,k,a[N];

int main() {
    cin>>T;
    while(T--){
        cin>>n>>k;
        for(int i=0;i<n;i++) a[i]=i;
        if(k!=n-1) swap(a[0],a[k]);//第一类构造
        else swap(a[0],a[n-2]),swap(a[n-2],a[n-3]);//第二类构造
        
        if(n==4 && k==3) cout<<-1<<'\n';//如果n=4&&k=n-1那么没有答案
        else {//输出分组
            for(int i=0;i<n/2;i++) cout<<a[i]<<" "<<a[n-i-1]<<'\n';
        }
    }
    
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值