解法1:AC
首先需要知道的是满足对于一个排列来说最多只有对,所以我们可以暴力把这存下来,紧接着是如何处理在里面选里面选。对于这个容斥就好了。根据容斥定理可以转化为求。其中代表从里面选取不同的并且满足的对数。
那么现在问题又转化为了如何快速求里面里面存在多少对满足。这个我们可以把拆分后的询问按照右端点排个序,并且把之前暴力求得对也按照右端点排个序存下来。我们从左到右枚举右端点的位置,对于 的时候 的时候,我们在一个树状数组中;然后对于,贡献为
时间复杂度,空间复杂度.
虽然说了那么多但是代码并不长。

const int N = 2e5+55;
int pos[N],c[N],ans[N];
vector<int>v[N];
struct node{
    int l,r,id,fg;
    node(){}
    node(int a,int b,int c,int d) :l(a),r(b),id(c),fg(d){}
    bool friend operator <(node a,node b) {
        return a.r<b.r;
    }
}Q[N*4];
class Solution {
public:
    void add(int k,int num) {
        for(; k<N; c[k]+=num,k+=k&(-k));
    }
    int Sum(int k) {
        int sum=0;
        for(; k>0; sum+=c[k],k-=k&(-k));
        return sum;
    }
    vector<int> PermutationQuery(int n, int q, int* p, int pLen, int* l1, int l1Len, int* r1, int r1Len, int* l2, int l2Len, int* r2, int r2Len) {
        // write code here
        for(int i=1;i<=n;i++) pos[p[i-1]]=i;
        for(int i=1;i<=n;i++) {//处理nlogn组S
            int val=i+i;
            while(val<=n) {
                int l=pos[val];
                int r=pos[i];
                if(l>r) swap(l,r);
                v[r].push_back(l);
                val+=i;
            }
        }
        int tot=0;
        for(int i=0;i<q;i++) {//拆分询问
            int a=l1[i],b=r1[i],c=l2[i],d=r2[i];
            a++,b++,c++,d++;
            if(c-b>1) Q[++tot]={b+1,c-1,i,1};
            Q[++tot]={a,c-1,i,-1};
            Q[++tot]={b+1,d,i,-1};
            Q[++tot]={a,d,i,1};
        }
        sort(Q+1,Q+1+tot);
        int pos=1;
        for(int i=1;i<=n;i++) {//从左到右枚举右端点位置
            for(auto j:v[i]) add(j,1);//把S中右端点为i的,在树状数组中左端点位置处的值+1
            while(pos<=tot&&Q[pos].r==i) {//处理拆分后询问的右端点为i的
                ans[Q[pos].id]+=Q[pos].fg*(Sum(Q[pos].r)-Sum(Q[pos].l-1));
                pos++;
            }
        }
        vector<int>v;
        for(int i=0;i<q;i++) v.push_back(ans[i]);
        return v;
    }
};

解法2:TLE
对于每一个值存下这个值出现的位置,然后对于每组询问枚举长度较小的区间去判断因子/倍数是不是在另外一个区间中就好了。
时间复杂度,空间复杂度

const int N = 2e5+55;
int pos[N];
class Solution {
public:
    vector<int> PermutationQuery(int n, int q, int* p, int pLen, int* l1, int l1Len, int* r1, int r1Len, int* l2, int l2Len, int* r2, int r2Len) {
        // write code here
        vector<int>v;
        for(int i=0;i<n;i++) pos[p[i]]=i;
        for(int id=0;id<q;id++) {
            int cnt=0;
            if(r1[id]-l1[id]>r2[id]-l2[id] ) {//遍历小的区间
                swap(l1[id],l2[id]);
                swap(r1[id],r2[id]);
            }
            for(int i=l1[id];i<=r1[id];i++) {
                int val=p[i];
                for(int j=2;j*j<=val;j++) {//找因子的贡献
                    if(val%j==0) {
                        if(j*j!=val) {
                            if(l2[id]<=pos[j]&&pos[j]<=r2[id]) cnt++;
                            if(l2[id]<=pos[val/j]&&pos[val/j]<=r2[id]) cnt++;
                        }else if(l2[id]<=pos[j]&&pos[j]<=r2[id]) cnt++;
                    }
                }
                if(l2[id]<=pos[1]&&pos[1]<=r2[id]) cnt++;//特判1的贡献
                val+=p[i];
                while(val<=n) {//找p[i]的倍数的贡献
                    if(l2[id]<=pos[val]&&pos[val]<=r2[id]) cnt++;
                    val+=p[i];
                }
            }
            v.push_back(cnt);
        }
        return v;
    }
};