codechef Starters 76
Not Divisible
题意:
给你一个 \(n\) ,请你构造一个数组 \(A\) ,满足如下条件:
- \(-500\leq A_i\leq500\)
- \(\forall (1\leq i<j\leq n)\) ,都有\(|A_i+A_{i+1}+...+A_j|\)不能被\((j-i+1)\)整除
思路:
题面大意为我们需要构造一个数组,使得数组中任意长度 \(>1\) 的连续子数组的和都不能被其长度整除
首先我们考虑以下,对于每一个长度 \(x\) ,它的倍数为 \(x,2x,3x...kx\)
我们现在希望找一种构造方式,如果可以让其 长度为 \(x\) 的 连续子数组的\(x<\sum A_i<2x\)
那么我们就达成了目标,我们知道要使得:\(\sum A_i=x\) 或者 \(\sum A_i=2x\)
一种方式就是让长度为 \(x\) 的连续子数组每一个数都为 \(1\) 或者 \(2\)
那么我们由此可以想到一种构造方式,可不可以让其都不满足,显然我们可以采取 \(1,2,1,2,1....\) 这种构造,让 \(1\) 与 \(2\) 相间摆放即可
这样对于\(\forall len>1\),由于我们是相间摆放:故我们长度为 \(len\) 的子数组不可能全为 \(1\) 也不可能全为 \(2\)
故一定有 \(len<\sum A_i<2len\)
所以这种构造方式可以满足题意要求
代码:
#include<bits/stdc++.h>
using namespace std;
void solve(){
int n;
cin>>n;
//1 2 1 2 1 2即可
for(int i=1;i<=n;i++){
if(i&1)cout<<1;
else cout<<2;
cout<<" \n"[i==n];
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cout<<fixed<<setprecision(12);
int t;
//t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
Contruct Array
题意:
给你一个 \(n\) ,请你构造一个数组 \(A\) , 满足以下条件,如果构造不出,请你输出 \(-1\)
-
\(-10^9\leq A_i \leq 10^9\)
-
设 \(P_i\) 表示\(A_1+A_2+...+A_i\),即数组\(A\)的前缀和
设 \(S_i\) 表示\(A_n+A_{n-1}+...+A_{n-i+1}\),即数组 \(A\) 的后缀和
要求对于\(\forall (1\leq i<n)\),若 \(i\) 是奇数,一定有\(P_i>S_i\),若 \(i\) 是偶数,一定有\(P_i<S_i\)
思路:
首先我们来分析一下什么时候无解:
当 \(n\) 是奇数的时候,一定无解
证明:
若 \(n\) 是奇数,其一定存在中心位置:\(n/2+1\)
我们不妨设\(n/2\)为奇数,那么\(n/2+1\)就为偶数
那么当 \(i=n/2\) 与 \(i=n/2+1\) 这两个位置有:
\(a_1+a_2+..+a_{n/2}>a_n+a_{n-1}+..+a_{n-n/2+1}\)
\(a_1+a_2+..+a_{n/2}+a_{n/2+1}<a_n+a_{n-1}+..+a_{n-n/2+1}+a_{n/2+1}\) \(<=>\) \(a_1+a_2+..+a_{n/2}<a_n+a_{n-1}+..+a_{n-n/2+1}\)
显然和上一个不等式矛盾,所以 \(n\) 为奇数一定无解
当 \(n\) 是偶数的时候,我们尝试构造:
我们可以考虑头尾对称这样来放置数:
\(1,-2,2........-2,2,-1\)
对于\(\forall i\)是奇数,一定有 \(P_i=1\),因为前缀的\(2\)和\(-2\)会被相互抵消,同理\(S_i=-1\)
对于\(\forall i\)是偶数,一定有 \(P_i=-1\),\(S_i=1\)
显然满足条件:
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+10;
int a[N];
void solve(){
//显然奇数一定无解
int n;
cin>>n;
if(n&1){
cout<<"-1\n";
return ;
}
for(int i=1,j=1,sign=1;i<=n/2;i++,j=2,sign*=-1){
a[i]=sign*j;
a[n-i+1]=-sign*j;
}
for(int i=1;i<=n;i++){
cout<<a[i]<<" \n"[i==n];
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cout<<fixed<<setprecision(12);
int t;
//t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
Bitwise Operations on Circle
题意:
你有一个长度为 \(n\) 的数组 \(c\) ,他们绕成一个圈,现在你有如下两种操作:
- 选择两个相邻的数 \(c_i\) 和 \(c_j\),将他们合并,结果为 \(c_i|c_j\)
- 选择两个相邻的数 \(c_i\) 和 \(c_j\),将他们合并,结果为 \(c_i\&c_j\)
你需要操作恰好 \((n-2)\) 次,此时数组会剩下两个数:\(X,Y\)
你希望 \(|X-Y|\) 的值尽可能大,请问这个值最大是多少?
思路:
首先我们要知道 \(|\) 操作时越或越大,而 \(\&\) 操作是越交越小的
即我们或操作会是数非严格单增,交操作会使数非严格单减
那么我们希望 \(|X-Y|\) 尽可能的大,那么我们肯定希望其中一个数尽可能大,另一个数尽可能小
故我们发现最优解当中,\(X\) 或者 \(Y\) 一定是只属于或操作或者交操作,即我们两个操作不会混
因为我们假设先把两个数或起来,然后再去和另一个数交,那么我这个数又可能会变小,所以我们贪心的极端想
最后我们一定会用或操作形成一个数,用交操作形成另一个数
现在问题就变成了,我们需要把一些数或起来,一些数交起来
我们考虑把破环成链,把数组展开成一个长度为\(2*n\)的样子:
\(a_1,a_2....a_n,a_1.....a_n\)
这样我们只要枚举开头,连续长度为 \(n\) 的一段,就一定对应着一种合并的链(这里类似与区间dp中环形石子合并的做法)
现在由于我们刚刚的结论,所以我们肯定是这一条链中,找到一段连续的前缀用或,然后剩下的后缀用交,形成了两个数
现在我们只要快速枚举计算答案即可,同时我们需要快速知道一个区间的或和交结果,我们可以采用 \(ST\) 表
然后我们再发现一个性质,就是我们多个数或的结果,由于我们所有数 \(c_i<2^{30}\) ,故我们或的结果最多只有\(30\)种不同的数
这样我们枚举链之后,用二分快速找到前缀不同的或结果,然后计算答案即可
时间复杂度为:\(N(logN)^2\)
代码:
#include<bits/stdc++.h>
using namespace std;
using LL = long long;
const int N=4e5+10;
int c[N];
int orf[N][25],andf[N][25]; //区间或,区间&
int lg2[N];
void solve(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>c[i];
}
for(int i=1;i<=n;i++){
c[i+n]=c[i];
}
for(int i=1;i<=n;i++){
lg2[i]=log2(i);
}
auto init=[&](){
for(int i=0;i<=20;i++){
for(int j=1;j+(1<<i)-1<=2*n;j++){
if(!i)orf[j][i]=c[j];
else orf[j][i]=orf[j][i-1]|orf[(1<<(i-1))+j][i-1];
}
}
for(int i=0;i<=20;i++){
for(int j=1;j+(1<<i)-1<=2*n;j++){
if(!i)andf[j][i]=c[j];
else andf[j][i]=andf[j][i-1]&andf[(1<<(i-1))+j][i-1];
}
}
};
init();
auto getor=[&](int l,int r){
int k=lg2[r-l+1];
return orf[l][k]|orf[r-(1<<k)+1][k];
};
auto getand=[&](int l,int r){
int k=lg2[r-l+1];
return andf[l][k]&andf[r-(1<<k)+1][k];
};
int ans=0;
for(int i=1;i<=n;i++){
int cur=i,L,R;
while(1){
ans=max(ans,abs(getor(i,cur)-getand(cur+1,i+n-1)));
//利用二分把所有不同的前缀or找出来
L=cur,R=i+n-1;
while(L<R){
int mid=(L+R+1)/2;
if(getor(i,cur)>=getor(i,mid))L=mid;
else R=mid-1;
}
cur=L+1;
if(cur>=i+n-1)break;
}
}
cout<<ans<<"\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cout<<fixed<<setprecision(12);
int t;
//t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}

浙公网安备 33010602011771号