【NOIP2016提高A组模拟9.21】整除

来源:互联网 发布:js拆分字符串 编辑:程序博客网 时间:2024/05/21 10:39

题目

  1. 【NOIP2016提高A组模拟9.21】整除 (Standard IO)
    Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits

Description

麦克雷有一个1~n的排列,他想知道对于一些区间,有多少对区间内的数(x,y),满足x能被y整除。

Input

第一行包含2个正整数n,m。表示有n个数,m个询问。
接下来一行包含n个正整数,表示麦克雷有的数列。
接下来m行每行包含2个正整数l,r。表示询问区间[l,r]。

Output

共 m 行,每行一个整数,表示满足条件的对数。

Sample Input

10 9
1 2 3 4 5 6 7 8 9 10
1 10
2 9
3 8
4 7
5 6
2 2
9 10
5 10
4 10

Sample Output

27
14
8
4
2
1
2
7
9

Data Constraint
30%:1<=n,m<=100
100%:1<=n,m<=2*10^5,1<=pi<=n

正解

我不会告诉你我懒得打tj的
令 X = [1, R] 的合法对数减去 [1, L - 1] 的合法对数,
Y = 一个数属于 [1, L - 1] 另一个数属于 [L, R] 的合法对数,
那么答案就是 X - Y。
我们先将询问按右端点升序排序。
并按原序列顺序从 1 往 n 做,每做到一个位置,便在它左边的数中与它有倍数关
系的数的位置加一。
并统计已经加的次数。
那么每当我们遇到一个右端点与当前做的位置相同时,就可以直接将当前总共加
的次数减去起点到左端点的区间的和就行了。
单点修改和区间求和可以用树状数组。

贴代码

var    tree:array[0..700005]of longint;    a,b:array[0..200005]of longint;    q:array[0..200005,1..3]of longint;    ans:array[0..200005]of longint;    i,j,k,l,m,n,x,tot,cc:longint;procedure qsort(l,r:longint);var    i,j,mid:longint;begin    i:=l;    j:=r;    mid:=q[(i+j) div 2,2];    repeat        while q[i,2]<mid do inc(i);        while q[j,2]>mid do dec(j);        if i<=j then        begin            q[0]:=q[i];            q[i]:=q[j];            q[j]:=q[0];            inc(i);            dec(j);        end;    until i>j;    if i<r then qsort(i,r);    if l<j then qsort(l,j);end;procedure change(x,l,r,v:longint);var    mid:longint;begin    if l=r then inc(tree[x]) else    begin        mid:=(l+r) div 2;        if v<=mid then change(x*2,l,mid,v) else change(x*2+1,mid+1,r,v);        tree[x]:=tree[x]+1;    end;end;procedure find(x,l,r,s,t:longint);var    mid:longint;begin    if t<s then exit;    if (l=s) and (r=t) then cc:=cc+tree[x] else    begin        mid:=(l+r) div 2;        if t<=mid then find(x*2,l,mid,s,t) else        if s>mid then find(x*2+1,mid+1,r,s,t) else        begin            find(x*2,l,mid,s,mid);            find(x*2+1,mid+1,r,mid+1,t);        end;    end;end;begin   // assign(input,'t3.in'); reset(input);   // assign(output,'t3.out'); rewrite(output);    readln(n,m);    for i:=1 to n do    begin        read(a[i]);        b[a[i]]:=i;    end;    readln;    for i:=1 to m do    begin        readln(q[i,1],q[i,2]);        q[i,3]:=i;    end;    qsort(1,m);    x:=0;    q[m+1,2]:=n*2;    q[0,2]:=0;    for i:=1 to n do    begin        while q[x,2]<i do inc(x);        if x>m then break;        for j:=1 to trunc(sqrt(a[i])) do        if a[i] mod j=0 then        begin            if b[j]<i then            begin                change(1,1,n,b[j]);                inc(tot);            end;            if j*j=a[i] then continue;            if b[a[i] div j]<i then            begin                change(1,1,n,b[a[i] div j]);                inc(tot);            end;        end;        j:=a[i];        while j<=n do        begin            if b[j]<=i then            begin                inc(tot);                change(1,1,n,b[j]);            end;            j:=j+a[i];        end;        while q[x,2]=i do        begin            cc:=0;            find(1,1,n,1,q[x,1]-1);            ans[q[x,3]]:=tot-cc;            inc(x);        end;    end;    for i:=1 to m do writeln(ans[i]);   // close(input); close(output);end.
0 0
原创粉丝点击