导航

mashup链接:https://codeforces.com/gym/518192

A. Friendly Arrays

参考博客:CodeTON Round 6 (Div 1 + Div 2, Rated, Prizes!)(A - E)

经典位运算,这里有个小trick,就是涉及到逻辑运算符的都把每一位拆开来看看影响
根据或运算的性质,对于a数列每个数的某一位来说,如果b数组中某个数在这一位上有1,那么在a数组的每个数的这一位都能保证变为1。而在后面按位异或时,如果a数列的长度为奇数,那么最后该位为1,偶数则为0.将这个操作类推到每一位,我们可以发现:如果a数列长度为奇数,通过任意次的或运算尽可能制造1,最后的异或和能达到最大,不操作则为最小。反过来,如果为偶数,不操作为最大,尽可能操作则为最小。

这里我们可以做一个预处理,在b数组输入时逐个进行或运算,然后得到一个含有最多1的数对a数组的数进行或运算。然后循环处理a数组即可。

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

void solve(){
    ll n,m; cin>>n>>m;
    vector<ll> a(n+1),b(m+1);
    ll ans=0;
    for(ll i=1;i<=n;i++){
        cin>>a[i];
        ans^=a[i];
    }
    ll k=0;
    for(ll i=1;i<=m;i++) {
        cin>>b[i];
        k|=b[i];
    }
    ll res=0;
    for(ll i=1;i<=n;i++){
        a[i]|=k;
        res^=a[i];
    }
    if(n%2==0) cout<<res<<" "<<ans<<"\n";
    else cout<<ans<<" "<<res<<"\n";
    
}
signed main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) {
        solve();
    }
}

B. Plus Minus Permutation

参考博客:Codeforces Round 895 (Div. 3)题解

每个数的位置是随意的,所以贪心的想,将所有数从大到小依次放在x数列、所有数从小到大放在y数列即可,计算出x、y数列的大小。再计算一下重合的部分(x、y的最小公倍数下标),各自减去重合的大小然后再做差就是答案。

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

void solve(){
    ll n,x,y; cin>>n>>x>>y;
    ll cntx=n/x;    //求n以内有多少个x的倍数
    ll cnty=n/y;
    ll gg=(x*y)/__gcd(x,y);  //求两数最小公倍数的公式
    ll cntc=n/gg;
    cntx-=cntc; cnty-=cntc;
    ll sumx=cntx*(n+n-cntx+1)/2;   //等差数列求和公式
    ll sumy=cnty*(1+cnty)/2;
    cout<<sumx-sumy<<"\n";
}
signed main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) {
        solve();
    }
}

C. Money Trees

参考博客:CF1873F Money Trees

二分答案。要求最长长度,想到可以二分答案。那么现在需要考虑如何快速验证答案是否正确,可以\(O(n)\) 枚举区间左端点,因为有了长度,所以可以直接获得右端点的值,直接验证右端点是否合法。
因为要求区间的每个数都是右边的数的倍数,所以可以提前预处理每个点最远的满足这个条件的右端点,直接判断合不合法。还要求和要小于某个值,这个直接前缀和预处理即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll n,k;
ll a[1000010],dis[1000010],h[1000010];

ll check(ll x){
    for(ll i=1;i<=n-x+1;i++) if(a[i+x-1]-a[i-1]<=k&&i+x-1<=dis[i]) return 1;
    return 0;
}

void solve(){
    cin>>n>>k;
    for(ll i=1;i<=n;i++) cin>>a[i],a[i]+=a[i-1];
    for(ll i=1;i<=n;i++) cin>>h[i];
    dis[n]=n;
    for(ll i=n-1;i>=1;i--){
        if(h[i]%h[i+1]==0) dis[i]=dis[i+1];
        else dis[i]=i;
    }
    ll l=0,r=n+1;
    while(l<=r){
        ll mid=l+r>>1;
        if(check(mid)){
            l=mid+1;
        }
        else r=mid-1;
    }
    cout<<l-1<<"\n";
}
signed main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int t;
    cin>>t;
    while(t--) {
        solve();
    }
}