数列互质

题目描述

给出一个长度为 的数列 ,以及 组询问 ,求区间 中有多少数在该区间中的出现次数与 互质。
输入格式
第一行,两个正整数 。

第二行, 个正整数 描述这个数列。

接下来 行,每行三个正整数 ,描述一次询问。
输出格式
输出 行,即每次询问的答案。
样例
样例输入

10 5
1 1 1 1 1 2 2 2 2 2
4 7 2
4 7 3
4 8 2
4 8 3
3 8 3
样例输出

0
2
1
1
0
数据范围与提示

a[i]<=n<=5*1e4

题解&&分析

这道题是真的恐怖,感觉自己还是太傻了
首先,我们不难想到用莫队解决这个问题,这样我们就可以把每个数在当前范围内的出现次数算出来
算一次的时间复杂度是根号n的时间复杂度。这也是这道题的重点,也就是说我们更改的数是不会超过根号n的。
我们就可以把出现次数的个数存起来,遍历过的点的次数存起来(每次都要存)然后跑一边循环,如果某一个次数满足条件,那么这类的次数都可以满足了

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <climits>
#include <cmath>
#include <algorithm>
#include <vector>
#define ll long long
using namespace std;
const int MAXN = 50003*4;
int n , m , k;
int belong[MAXN];
struct node{
    int l , r , id , k;
    friend bool operator < ( node a , node b ){
        if( belong[a.l] ^ belong[b.l] )
            return belong[a.l] < belong[b.l];
        if( belong[a.l] & 1 )
            return belong[a.r] < belong[b.r];
        return belong[a.r] > belong[b.r];
    }
}ques[MAXN];
ll ans[MAXN];
int a[MAXN];
ll sum[MAXN];
int que[MAXN] , tot;
void read( int &x ){
    x = 0;char s = getchar();
    while( s < '0' || s > '9' )
        s = getchar();
    while( s >= '0' && s <= '9' ){
         x= x * 10 + s - '0';
    s = getchar();
    }

}
int cf[MAXN];
int gcd( int x , int y ){
    if( !y ) return x;
    return gcd( y , x % y );
}
bool flag[MAXN];
int main(){
    read( n );read( m );
    for( int i = 1 ; i <= n ; i++ ){
        read( a[i] );
    }
    int cnt = sqrt( n );
    int dnum = ceil( (double) n / cnt );
    for( int i = 1 ; i <= dnum ; i ++ ){
        for( int j = ( i - 1 ) * cnt + 1 ; j <= min( n , i * cnt ) ; j ++ )
            belong[j] = i;
    }
    for( int i = 1 ; i <= m ; i ++ ){
        read( ques[i].l );read( ques[i].r );
        read( ques[i].k );
        ques[i].id = i;
    }
    sort( ques + 1 , ques + m + 1 );
    int l = 1  , r = 0;
    //printf( "%d\n" , sum[1] );
    for( int i = 1 ; i <= m ; i ++ ){
        while(l < ques[i].l){
            --sum[a[l]];
            cf[sum[a[l]]] ++ , cf[sum[a[l]]+1] --;
            que[++tot] = sum[a[l]];
            l++;
        }
        while(l > ques[i].l) {
            l --;
            sum[a[l]]++;
            cf[sum[a[l]]] ++ , cf[sum[a[l]]-1] --;
            que[++tot] = sum[a[l]];
        }
        while(r < ques[i].r){
            r ++;
            sum[a[r]]++;
            cf[sum[a[r]]] ++ , cf[sum[a[r]]-1] --;
            que[++tot] = sum[a[r]];
        }
        while(r > ques[i].r){
            --sum[a[r]];
            cf[sum[a[r]]] ++ , cf[sum[a[r]]+1] --;
            que[++tot] = sum[a[r]];
            r --;
        }
        int k = 0;
        for( int j = 1 ; j <= tot ; j ++ ){
            if( flag[que[j]] == 0 && cf[que[j]] > 0 ){
                if( gcd( que[j] , ques[i].k ) == 1 )
                    ans[ques[i].id] += cf[que[j]];
                flag[que[j]] = 1;
                que[++k] = que[j];
            }
        }
        tot = k;
        for( int j = 1 ; j <= tot ; j ++ )
            flag[que[j]] = 0;
    }
    for( int i = 1 ; i <= m ; i ++ )
        printf( "%lld\n" , ans[i] );
    return 0;
}

发布了68 篇原创文章 · 获赞 7 · 访问量 3853

猜你喜欢

转载自blog.csdn.net/weixin_43823476/article/details/96472970