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

这是一道关于区间蚂蚁决斗问题的算法题目,主要考察区间GCD与区间统计。给定蚂蚁序列和一系列区间询问,若蚂蚁ai能被aj整除,ai的战斗点加一,当战斗点等于区间长度时蚂蚁存活。利用线段树维护区间最小值、出现次数和GCD,通过判断区间GCD与最小值的关系来计算被吃掉的蚂蚁数量。
摘要由CSDN通过智能技术生成

原题链接
在这里插入图片描述

题意:给你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<bits/stdc++.h>
#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();
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值