Codeforces Round #769 (Div. 2)思路分享
Codeforces Round #769 (Div. 2)
咕的最久的一场比赛.....当时被C卡住,真的让我自闭了许久。。。
A. ABC
发现合法的方案只有01和10,其余均为不合法。
B. Roof Construction
B题当时真的卡了我许久....
由于数字时0到n-1,也就是说二进制是从0,一个一个往上加的。考虑最高的位数,将所有的数字按照最高位是0,是1分成两堆。可以发现无论怎么安排,总有两个数异或起来会使最高位的1异或出来。最以最大值最小只能是最高位为1,其他位为0.方案也简单,将两拨分开放,中间交界处放0与1<<k即可。
C. Strange Test
真的没有看清楚a,b的数据范围.....一直在找什么贪心....结果卡住gg...
考虑我们使用过操作三后,一定存在a>=b,那么我们只能让b一直加1来与a相等。所以最后的结果一定是a加到某个数后,然后a|b,之后b++.或者b先加到某个数后,a|b,之后a++.因为数据大小都是1e6,所以我们直接枚举即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int T,a,b;
int main()
{
// freopen("1.in","r",stdin);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&a,&b);
int ans=b-a;
for(int i=1;i<=ans;++i)
{
if(((a+i-1)|b)==b)
{
ans=i;
break;
}
}
for(int i=1;i<=ans;++i)
{
if((a|(b+i-1))==b+i-1)
{
ans=i;
break;
}
}
printf("%d\n",ans);
}
return 0;
}
D. New Year Concert
题目要求前k个序列构成合法的序列,使得每个区间的gcd都不等于区间的长度。
首先想到的就是如果我们要修改的话,那么我们最优的就是将它修改成一个大质数,这样的话包括他在内的gcd都只能是1,造成的结果最优。并且修改后,整个序列就从修改的位置分开。
接下来我们就贪心的干,需要修改的话就修改就行了。现在的问题就是当我们添加一个数时,如何判断这个数需不需要修改。最朴素的想法就是将包含这个数的所有区间检查一遍,但这显然会超时....我们需要继续找性质....注意到:当我们从当前数向前扩展时,它的gcd只能不变或减小,而区间长度会增加。正好两者具有相反的单调性。假设存在某个区间不合法的话(即gcd=区间长度),那么之后他们的gcd与区间长度的大小关系正好相反。同时我们也很容易看出来最多只有一个区间不合法。这样直接二分。同时我们需要:随时查询某个区间的gcd,动态修改。直接套线段树就行了。
点击查看代码
#include<bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int N=2e5+10;
int n,a[N];
struct Tree
{
int l,r,dat;
#define l(p) t[p].l
#define r(p) t[p].r
#define dat(p) t[p].dat
}t[N<<2];
inline int gcd(int a,int b) {return b?gcd(b,a%b):a;}
inline void build(int p,int l,int r)
{
l(p)=l;r(p)=r;
if(l==r) return;
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
}
inline void alter(int p,int x,int v)
{
if(l(p)==r(p)) {dat(p)=v;return;}
int mid=l(p)+r(p)>>1;
if(x<=mid) alter(ls,x,v);
else alter(rs,x,v);
dat(p)=gcd(dat(ls),dat(rs));
}
inline int ask(int p,int l,int r)
{
if(l<=l(p)&&r>=r(p)) return dat(p);
int mid=l(p)+r(p)>>1;
int ans=0;
if(l<=mid) ans=gcd(ans,ask(ls,l,r));
if(r>mid) ans=gcd(ans,ask(rs,l,r));
return ans;
}
inline bool check(int l,int r)
{
if(a[r]>=1&&ask(1,l,r)<=r-l+1)
{
int L=l,R=r;
while(L<R)
{
int mid=L+R+1>>1;
if(ask(1,mid,r)<=r-mid+1) L=mid;
else R=mid-1;
}
if(ask(1,L,r)==r-L+1) return true;
return false;
}
return false;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
build(1,1,n);
alter(1,1,a[1]);
int l=1,ans=0;
for(int i=1;i<=n;++i)
{
alter(1,i,a[i]);
if(check(l,i))
{
l=i+1;
++ans;
}
printf("%d ",ans);
}
return 0;
}