题目链接:
题目大意:
给出一些数,每次给出一个区间,所有的数两两比较,如果a能整除b得一分,b能整除a得一分,问没有得满分的有多少个。
题目分析:
- 我们可以知道,每个区间的数最多只有一种数字满足条件,也就是所有数的gcd,那么我们利用线段树,维护某一个区间的gcd,和这个gcd出现的次数即可,无修改的线段树水题
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define MAX 100007
using namespace std;
typedef pair<int,int> PII;
int n,m;
int a[MAX];
struct Tree
{
int l,r,gcd,num;
}tree[MAX<<2];
int gcd ( int a , int b )
{
return !b?a:gcd(b,a%b);
}
void push_up ( int u )
{
int a = tree[u<<1].gcd;
int b = tree[u<<1|1].gcd;
int x = tree[u<<1].num;
int y = tree[u<<1|1].num;
int d = gcd ( a , b );
tree[u].gcd = d;
tree[u].num = 0;
if ( d == a )
tree[u].num += x;
if ( d == b )
tree[u].num += y;
}
void build ( int u , int l , int r )
{
tree[u].l = l;
tree[u].r = r;
if ( l == r )
{
tree[u].gcd = a[l];
tree[u].num = 1;
return;
}
int mid = l+r>>1;
build ( u<<1 , l , mid );
build ( u<<1|1 , mid+1 , r );
push_up ( u );
}
PII query ( int u , int left , int right )
{
int l = tree[u].l;
int r = tree[u].r;
if ( left <= l && r <= right )
return make_pair ( tree[u].gcd , tree[u].num );
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 ( )
{
while ( ~scanf ( "%d" , &n ) )
{
for ( int i = 1 ; i <= n ; i++ )
scanf ( "%d" , &a[i] );
build ( 1 , 1 , n );
scanf ( "%d" , &m );
while ( m-- )
{
int l,r;
scanf ( "%d%d" , &l , &r );
printf ( "%d\n" , r-l+1-query ( 1, l , r ).second );
}
}
}