CF1946F 题解
思路
注意到给出的是一个排列,也就是每个数只会出现一次。所以如果枚举倍数或因数,总复杂度都是
考虑对整个序列怎么做,设
再扩展到区间询问。考虑把所有询问离线下来,然后从后往前依次处理整个序列,
考虑如何计算
这样处理完所有
代码
代码中预处理了
#include<iostream>
#include<algorithm>
#include<vector>
#define int long long
#define pii pair<int,int>
using namespace std;
const int N=1e6+10;
int n,q,d[N],a[N],pos[N],res[N];
vector <pii> ask[N];
vector <int> tp[N];
struct bit
{
int b[N];
void clear() {for(int i=0;i<=n;i++) b[i]=0;}
int lowbit(int x) {return x&(-x);}
void add(int p,int k) {for(;p<=n;p+=lowbit(p)) b[p]+=k;}
int query(int p) {int tr=0; for(;p;p-=lowbit(p)) tr+=b[p]; return tr;}
}f;
void sol()
{
cin>>n>>q,f.clear();
for(int i=1;i<=n;i++) cin>>a[i],pos[a[i]]=i,ask[i].clear(),tp[i].clear();
for(int i=1;i<=n;i++)
{
for(int j=a[i]*2;j<=n;j+=a[i]) if(pos[j]>i) tp[i].push_back(pos[j]);
sort(tp[i].begin(),tp[i].end());
}
for(int i=1,l,r;i<=q;i++) cin>>l>>r,ask[l].push_back({r,i});
for(int i=n;i>=1;i--)
{
f.add(i,1);
for(int j:tp[i]) d[j]=1;
for(int j:tp[i]) for(int k:tp[j]) d[k]+=d[j];
for(int j:tp[i]) f.add(j,d[j]);
for(pii te:ask[i]) res[te.second]=f.query(te.first);
}
for(int i=1;i<=q;i++) cout<<res[i]<<' ';
cout<<'\n';
}
signed main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
int TT; cin>>TT;
while(TT--) sol();
return 0;
}