質問アドレス: http://codeforces.com/contest/474/problem/F
質問の意味から、最終的に残せるものは区間内の最小の gcd でなければならないことがわかります。次に、区間内の gcd の最小値に等しい数値に変換されます。間隔の最小 gcd は間隔の最小値以下である必要があるため、最小値の数のみが必要です。次に、r-l+1-number を使用します。
上記の情報については、線分ツリーを使用して維持できます。間隔 gcd、間隔最小値、間隔最小値の数をそれぞれ維持します。
コードは次のとおりです:
#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <stdlib.h>#include <math.h>#include <ctype.h>#include <queue>#include <map>#include <set>#include <algorithm>using namespace std;#define LL __int64#define lson l, mid, rt<<1#define rson mid+1, r, rt<<1|1const int INF=0x3f3f3f3f;const int MAXN=100000;int minv[MAXN<<2], gcd[MAXN<<2], num[MAXN<<2], q_minv, q_gcd, q_num;int getgcd(int a, int b){ return a==0?b:getgcd(b%a,a);}void PushUp(int rt){ minv[rt]=min(minv[rt<<1],minv[rt<<1|1]); gcd[rt]=getgcd(gcd[rt<<1],gcd[rt<<1|1]); if(minv[rt<<1]==minv[rt<<1|1]) num[rt]=num[rt<<1]+num[rt<<1|1]; else if(minv[rt<<1]>minv[rt<<1|1]) num[rt]=num[rt<<1|1]; else num[rt]=num[rt<<1];}void build(int l, int r, int rt){ if(l==r) { scanf("%d",&minv[rt]); num[rt]=1; gcd[rt]=minv[rt]; return ; } int mid=l+r>>1; build(lson); build(rson); PushUp(rt);}void query(int ll, int rr, int l, int r, int rt){ if(ll<=l&&rr>=r) { q_gcd=getgcd(q_gcd,gcd[rt]); if(minv[rt]==q_minv) { q_num+=num[rt]; } else if(minv[rt]<q_minv) { q_num=num[rt]; q_minv=minv[rt]; } return ; } int mid=l+r>>1; if(ll<=mid) query(ll, rr, lson); if(rr>mid) query(ll,rr,rson);}int main(){ int n, m, i, l, r; scanf("%d",&n); build(1, n, 1); /*for(i=1;i<=9;i++) { printf("%d %d %d\n",minv[i], gcd[i], num[i]); }*/ scanf("%d",&m); while(m--) { scanf("%d%d",&l,&r); q_minv=INF; q_gcd=0; q_num=0; query(l,r,1,n,1); if(q_gcd==q_minv) { printf("%d\n",r-l+1-q_num); } else { printf("%d\n",r-l+1); } } return 0;}