题目描述
给出一个长度为 的数列 ,以及 组询问 ,求区间 中有多少数在该区间中的出现次数与 互质。
输入格式
第一行,两个正整数 。
第二行, 个正整数 描述这个数列。
接下来 行,每行三个正整数 ,描述一次询问。
输出格式
输出 行,即每次询问的答案。
样例
样例输入
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;
}