題面
題解
考慮CDQ分治。對於\(solve(l,r,v)\)(其中l,r表示當前處理到的區間的左右端點,v是一個vector,存放當前區間內待處理的所有詢問的序號):
-
設\(m=(l+r)>>1\)。
-
預處理出\(f[i][j](1{\leq}i{\leq}k,l{\leq}j{\leq}r)\),其中\(f[i][j]=\)
\[\begin{cases} {以j為左端點,右端點{\leq}m,且a[右端點]=i的不下降子序列數}(l{\leq}j{\leq}m) \\ {以j為右端點,左端點{>m,且a[左端點]=i的不下降子序列數(m<j{\leq}r)}} \end{cases} \]對於\(m<j{\leq}r\)來言,有遞推式
\[f[i][j]={\sum\limits_{m<k<j,a[k]{\leq}a[j]}}f[i][k]+[a[j]=i]$$,這一過程可以用樹狀數組優化,從而在$O((r-l+1)klogk)$時間內完成預處理。 另外,需要將空字符串統計進去,就是把$f[1][m],f[k][m+1]$都加1。 接下來,對$f$進行前綴和,就可以得到$f[i][j]=$ $$\begin{cases} {l{\leq}左端點,右端點{\leq}m,且a[右端點]=i的不下降子序列數}(l{\leq}j{\leq}m) \\ {j{\geq}右端點,左端點{>m,且a[左端點]=i的不下降子序列數(m<j{\leq}r)}} \end{cases}\] -
遍歷所有序號\(id{\in}v\)。如果\(R[id]{\leq}m\),將其加入數組vl。如果\(L[id]>m\),將其加入數組vr。
-
對於其余id,統計答案:
\[{\sum\limits_{i=1}^{k}}f[i][L[id]]{\sum\limits_{j=i}^{k}}f[j][R[id]]$$。這一過程可以先計算前綴和來優化。 \]
依此過程,solve中預處理的總復雜度是\(O(nklognlogk)\),統計答案的總復雜度是\(O(qk)\)。
代碼
#include<bits/stdc++.h>
using namespace std;
#define N 50000
#define Q 200000
#define ll long long
#define mod 1000000007
#define rg register
namespace ModCalc{
inline void Inc(ll &x,ll y){
x += y;if(x >= mod)x -= mod;
}
inline void Dec(ll &x,ll y){
x -= y;if(x < 0)x += mod;
}
inline ll Add(ll x,ll y){
Inc(x,y);return x;
}
inline ll Sub(ll x,ll y){
Dec(x,y);return x;
}
}
using namespace ModCalc;
inline ll read(){
ll s = 0,ww = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
return s * ww;
}
inline void write(ll x){
if(x < 0)putchar('-'),x = -x;
if(x > 9)write(x / 10);
putchar('0' + x % 10);
}
ll n,q,k;
ll f[20+5][N+5],a[N+5],L[Q+5],R[Q+5];
ll ans[Q+5];
ll s[20+5];
struct BIT{
ll b[20+5];
inline ll lowbit(ll x){
return x & -x;
}
inline void reset(){
memset(b,0,sizeof(b));
}
inline void ud(ll x,ll dx){
for(rg ll i = x;i <= k;i += lowbit(i))Inc(b[i],dx);
}
inline ll query(ll x){
ll rt = 0;
for(rg ll i = x;i;i -= lowbit(i))Inc(rt,b[i]);
return rt;
}
}B;
inline void solve(ll l,ll r,vector<ll>v){
if(l == r){
for(rg ll i = 0;i < v.size();i++)ans[v[i]] = 2;
return;
}
ll m = (l + r) >> 1;
for(rg ll st = 1;st <= k;st++){
B.reset();
for(rg ll i = m + 1;i <= r;i++){
f[st][i] = B.query(a[i]);
if(a[i] == st)Inc(f[st][i],1);
B.ud(a[i],f[st][i]);
}
for(rg ll i = m + 2;i <= r;i++)Inc(f[st][i],f[st][i-1]);
}
for(rg ll st = 1;st <= k;st++){
B.reset();
for(rg ll i = m;i >= l;i--){
f[st][i] = B.query(k + 1 - a[i]);
if(a[i] == st)Inc(f[st][i],1);
B.ud(k + 1 - a[i],f[st][i]);
}
for(rg ll i = m - 1;i >= l;i--)Inc(f[st][i],f[st][i+1]);
}
for(rg ll i = l;i <= m;i++)Inc(f[1][i],1); //左半部分為空子串
for(rg ll i = m + 1;i <= r;i++)Inc(f[k][i],1); //右半部分為空子串
vector<ll>vl,vr;
vl.resize(0);
vr.resize(0);
for(rg ll i = 0;i < v.size();i++){
ll id = v[i];
if(R[id] <= m)vl.push_back(id);
else if(L[id] > m)vr.push_back(id);
else{
for(rg ll j = k;j >= 1;j--)s[j] = Add(s[j+1],f[j][R[id]]);
for(rg ll j = 1;j <= k;j++)Inc(ans[id],f[j][L[id]] * s[j] % mod);
}
}
if(vl.size())solve(l,m,vl);
if(vr.size())solve(m+1,r,vr);
}
vector<ll>v;
int main(){
n = read(),k = read();
for(rg ll i = 1;i <= n;i++)a[i] = read();
q = read();
for(rg ll i = 1;i <= q;i++)L[i] = read(),R[i] = read();
v.resize(0);
for(rg ll i = 1;i <= q;i++)v.push_back(i);
solve(1,n,v);
for(rg ll i = 1;i <= q;i++)write(ans[i]),putchar('\n');
return 0;
}