2024.4.16 训练1(VP) CodeForces自创MashUP训练赛(rating1200-1400)
Posted on 2024-04-16 11:38 qiujian222 阅读(80) 评论(0) 编辑 收藏 举报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();
}
}