Codeforces Round #271 (Div. 2) F. Ant colony【線段樹】【數論】

題目鏈接:https://codeforc.es/problemset/problem/474/F

題目大意:給定一個長度爲nn的序列,tt次詢問區間[l,r][l,r]內不能活下來的數量,規則爲:區間內任意兩個數比較,若一個數能整除另一個數,則這個數的積分+1,所有數比完之後,若當前數積分==rl==r-l,則這個數能活下來。

思路:若這個區間內存在這樣的數,那麼這樣的數肯定是區間最小的,且是區間其他數的因數,那麼我們可以用線段樹維護每次查詢的區間,若某兩個小區間能夠合併,那麼一定滿足:小區間的最小數gcdgcd是其他數的倍數,並且此時要更新這個區間內最小數的數量cntcnt

AC代碼:

#include<bits/stdc++.h>
using namespace std;
#define Mid ((l+r)>>1)
#define lson rt<<1,l,Mid
#define rson rt<<1|1,Mid+1,r
const int maxn=1e5+10;
int b[maxn];
struct  node
{
    int l,r,cnt,gcd;
}a[maxn<<2];
int gcd(int x,int y){
    return y==0?x:gcd(y,x%y);
}
void push_up(int rt){
    int t=gcd(a[rt<<1].gcd,a[rt<<1|1].gcd);
    a[rt].gcd=t;
    a[rt].cnt=0;
    if(t==a[rt<<1].gcd){
        a[rt].cnt+=a[rt<<1].cnt;
    }
    if(t==a[rt<<1|1].gcd){
        a[rt].cnt+=a[rt<<1|1].cnt;
    }
}
void build(int rt,int l,int r){
    a[rt].l=l;
    a[rt].r=r;
    if(l==r){
        a[rt].gcd=b[l];
        a[rt].cnt=1;
        return ;
    }
    build(lson);
    build(rson);
    push_up(rt);
}
typedef pair<int,int> pii;
pii query ( int u , int left , int right )
{
    int l = a[u].l;
    int r = a[u].r;
    if ( left <= l && r <= right )
        return make_pair ( a[u].gcd , a[u].cnt );
    pii ret,temp;
    ret.first = -1;
    int mid = l+r>>1;
    if ( left <= mid && right >= l ) 
        ret = query ( u<<1 , left , right );
    if ( left <= r && right > mid )
    {
        temp = query ( u<<1|1 ,left , right );
        if ( ret.first == -1 ) ret = temp;
        else
        {
            int d = gcd ( ret.first , temp.first );
            if ( d != ret.first ) ret.second = 0;
            if ( d == temp.first ) ret.second += temp.second;
            ret.first = d;
        }
    }
    return ret;
}
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&b[i]);
    }
    build(1,1,n);
    int t;
    scanf("%d",&t);
    while(t--){
        int l,r;
        scanf("%d%d",&l,&r);
        pii tmp=query(1,l,r);
        int ans=r-l+1-tmp.second;
        printf("%d\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章