CF474F.Ant colony(线段树+策略)

原题链接
CF474F.Ant colony(线段树+策略)_第1张图片

题意:给你n只蚂蚁,q个询问,对于询问来说,你可以任意选择一个区间[l,r],之后这里的蚂蚁就会相互之间作战,那么当ai和aj决斗时,如果ai能够被aj整除,那么ai的战斗点+1,当且仅当蚂蚁的战斗点为r-l的时候才不用被吃掉,让你求询问的区间,一共吃掉了多少个蚂蚁,样例:[1, 3, 2, 4 ,2]询问区间[1, 5]的时候它们分别的战斗点为[4, 0, 2, 0, 2]

解法:一开始想到了区间gcd,但是考虑1的情况时候考虑了很久,之后考虑了如果区间的gcd等于最小值,说明现在最小值能够被其它所有数整除,那么当前的答案就是r-l+1-minsize,如果当前区间的gcd不等于最小值,说明当前的区间的每一个数至少存在一个数不是它的倍数,那么就得到答案了。

写法:利用线段树维护区间最小,区间最小值出现得次数,区间gcd,没有修改就是简单题啦_

#include
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define ll long long
#define sc scanf
#define pr printf
#define lson u << 1
#define rson u << 1|1
using namespace std;
const int maxn = 1e5 + 5;
int gcd(int a, int b){
	return b?gcd(b,a%b):a;
}
struct node{
	int minv;//区间最小 
	int num;//区间最小值出现次数 
	int gc;//区间gcd 
}tr[maxn*4];
void build(int u, int l, int r){
	if(l == r){
		sc("%d",&tr[u].minv);
		tr[u].num = 1;
		tr[u].gc = tr[u].minv;
		return ;
	}
	int mid = (l + r) >> 1;
	build(u << 1, l, mid);
	build(u << 1|1, mid+1, r);
	
	if(tr[lson].minv > tr[rson].minv){
		//如果当前左区间小于右区间
		tr[u].minv = tr[rson].minv;
		tr[u].num = tr[rson].num;
	}else if(tr[lson].minv < tr[rson].minv){
		tr[u].minv = tr[lson].minv;
		tr[u].num = tr[lson].num;
	}else{
		tr[u].minv = tr[lson].minv;
		tr[u].num = tr[lson].num + tr[rson].num;
	}
	tr[u].gc = gcd(tr[lson].gc,tr[rson].gc);
}


int minv,min_num,gc;
void query(int L, int R, int u, int l, int r){
	if(L <= l && R >= r){
		if(minv > tr[u].minv){
			minv = tr[u].minv;
			min_num = tr[u].num;
		}else if(minv == tr[u].minv){
			min_num += tr[u].num;
		}
		gc = gcd(gc,tr[u].gc);
		return ;
	}
	int mid = (l + r) >> 1;
	if(L <= mid)query(L,R,lson,l,mid);
	if(R > mid)query(L,R,rson,mid+1,r);
}
void solve(){
	int n;
	scanf("%d",&n);
	build(1, 1, n);
	int q;
	sc("%d",&q);
	while(q--){
		int l,r;
		sc("%d%d",&l,&r);
		gc = 0, minv = 0x3f3f3f3f,min_num = 0;
		query(l,r,1,1,n);
//		printf("min = %d gc = %d size = %d\n",minv,gc,min_num);
		if(minv == gc){
			pr("%d\n",r-l+1-min_num);
			continue;
		}
		pr("%d\n",r-l+1);
	}
}
int main(){
//    freopen("2.in","r",stdin);
//    freopen("2.out","w",stdout);
//    IOS;
    int t;
    t = 1;
//    cin >> t;
//    scanf("%d",&t);
    while(t--)solve();
} 

你可能感兴趣的:(CF1600分以上训练,数论)