C. Strange Test
题意:给出两个数a和b (a<b),每次可以从以下三个操作中选一个:1.a=a+1; 2.b=b+1; 3.a=a|b. 求使a和b相等所需最小操作数。(the sum of b is less than 1e6)
解:a小于b嘛,那当它们尾数一样的时候或运算一下,就相等了。现在考虑怎么让它们尾数一样。很简单,要么加a,要么加b。那就两个都试一遍。直接算有点烦,尤其是a,那就枚举。a枚举到b就可以了,b的话,题目把b的和小于1e6加深,疯狂暗示枚举个十倍八倍的也不成问题。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 1000005 #define maxn 1005 #define maxm 305 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int a,b; signed main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d",&a,&b); int ans=b-a; for(int i=a;i<=b;i++){ if((i|b)==b) ans=min(ans,i-a+1); } for(int i=b;i<=b<<2;i++){ if((i|a)==i) ans=min(ans,i-b+1); } printf("%d\n",ans); } return 0; }
D. New Year Concert
题意:给出一串数。对于它的每一个前缀,求最少修改多少个数后,能使它的每一个子数组的gcd,不等于这个子数组的长度。(不加逗号要断气了
解:肉眼观察一下,首先这串数里不能有1。其次连着两个的不能都是2的倍数,连着3个的不能是3的倍数,etc。如果修改一个数,那么包含这个数的任意子数组都可以符合要求。
既然要一个一个输出答案,那么考虑一个一个往里加数。加之前假设这串数已经满足要求了,那么可以不动其中的任何一个,只考虑包含新加进来数的子数组。但是每个都算一遍还是n2,会超时。有一种感觉是之前长度已经很长的子数组,加入新的一个数多半还是满足要求的。考虑寻找这个分界点。已知gcd越加越小,那么之前gcd已经小于长度的子数组多加进来一个数,显然满足要求,那么每次可以跳过这些数。如果之前gcd比长度大,那加进来一个新的数就有可能相等了,有嫌疑,留着。如果找到违规子数组,优先修改末尾,也就是新加进来的数,这样后面的都不用判了。(改第一个的话样例三会提醒你,说,谢谢样例三。
然后就是快速求区间gcd,懒人专供线段树,不知道为什么开4倍空间过不去,非要8倍,那就8倍吧。
代码:
#include <bits/stdc++.h> using namespace std; #define ll long long #define maxx 200005 #define maxn 1005 #define maxm 305 #define eps 0.00000001 #define inf 0x7fffffff #define mod 998244353 //#define int long long int n,a[maxx]; int gcd(int a,int b){ return b==0?a:gcd(b,a%b); } int tr[maxx<<4]={0}; void build(int now,int l,int r){ if(l==r) { tr[now] = a[l]; return; } int mid=(l+r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); tr[now]=gcd(tr[now*2],tr[now*2+1]); } int query(int now,int l,int r,int s,int e){ if(s<=l&&r<=e) return tr[now]; int a=0,b=0; int mid=(l+r)/2; if(s<=mid) a=query(now*2,l,mid,s,e); if(mid<e) b=query(now*2+1,mid+1,r,s,e); return gcd(a,b); } signed main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); int j=1,ans=0; for(int i=1;i<=n;i++){ while(query(1,1,n,j,i)<i-j+1) j++; if(query(1,1,n,j,i)==i-j+1){ ans++; j=i+1; } printf("%d ",ans); } printf("\n"); return 0; }