acdream 1070 神奇的%系列二 (离线操作)

题意:

给出一个序列,然后又q个询问,每个询问给出[L,R],求区间中能整除X的数的个数。

题解:

这题类似于线段树,要求整除x的数的个数,其实就是求是X的因子的个数,我们首先打出1-maxn内的因子表。然后根据题目将L和R都向X连一条边,之后用离线操作统计区间[1,L],[1,R]因子的个数。具体做法看代码。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define B(x) (1<<(x))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
void cmax(ll& a,ll b){ if(b>a)a=b; }
void cmin(ll& a,ll b){ if(b<a)a=b; }
void add(int& a,int b,int mod){ a=(a+b)%mod; }
void add(ll& a,ll b,ll mod){ a=(a+b)%mod; }
const int oo=0x3f3f3f3f;
const ll OO=0x3f3f3f3f3f3f3f3f;
const ll MOD=1000000007;
const int maxn = 100005;
int a[maxn];
vector<int>fac[maxn];
struct EDGE{
    int v,id,next;
}E[maxn<<1];
int head[maxn<<1],tol;
int ans[maxn],num[maxn];

void get_fac(){
    for(int i=1;i<maxn;i++)
        for(int j=i;j<maxn;j+=i)
            fac[j].push_back(i);
}

void Init(){
    memset(head,-1,sizeof head);
    tol=0;
}

void add_edge(int u,int v,int id){
    E[tol].v=v;
    E[tol].id=id;
    E[tol].next=head[u];
    head[u]=tol++;
}

int main(){
    //freopen("G:\\read.txt","r",stdin);
    int n,val,q,L,R,X;
    get_fac();
    while(scanf("%d",&n)!=EOF){
        Init();
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        scanf("%d",&q);
        for(int i=1;i<=q;i++){
            scanf("%d %d %d",&L,&R,&X);
            add_edge(L-1,X,i);
            add_edge(R,X,i);
            ans[i]=-1;
        }
        memset(num,0,sizeof num);
        for(int i=1;i<=n;i++){
            num[a[i]]++;
            for(int j=head[i];j!=-1;j=E[j].next){
                int v=E[j].v,id=E[j].id,SIZE=fac[v].size();
                int res=0;
                for(int k=0;k<SIZE;k++)
                    res+=num[fac[v][k]];
                if(ans[id]!=-1) ans[id]=res-ans[id];
                else ans[id]=res;
            }
        }
        for(int i=1;i<=q;i++)
            printf("%d\n",ans[i]);
    }
    return 0;
}




你可能感兴趣的:(acdream 1070 神奇的%系列二 (离线操作))