解法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; } };