洛谷[USACO23FEB] Piling Papers G
题目大意
给你一个长度为 n n n的序列 a a a,满足 1 ≤ a i ≤ 9 1\leq a_i\leq 9 1≤ai≤9,以及两个整数 A , B A,B A,B。有 q q q次询问,每次询问给出 l , r l,r l,r。对于每次询问,一开始有一个空串,对 a l , a l + 1 , … , a r a_l,a_{l+1},\dots,a_r al,al+1,…,ar依次操作,对于每一个 a i a_i ai,你可以选择将 a i a_i ai放在 x x x的前面、后面、或者什么也不做。最后,将 x x x中的数字依次相连得到一个整数,求能使这个整数在 [ A , B ] [A,B] [A,B]之间的方案数的数量,输出对 1 0 9 + 7 10^9+7 109+7取模。
1 ≤ n ≤ 300 , 1 ≤ A , B ≤ 1 0 18 1\leq n\leq 300,1\leq A,B\leq 10^{18} 1≤n≤300,1≤A,B≤1018
题解
用差分将要求的部分变为 [ 0 , B ] [0,B] [0,B]的方案数减去 [ 0 , A − 1 ] [0,A-1] [0,A−1]的方案数,那么我们只需考虑求 [ 0 , k ] [0,k] [0,k]的方案数。
设 f i , l , r , 0 / 1 / 2 f_{i,l,r,0/1/2} fi,l,r,0/1/2表示前 i i i个数形成的 r − l + 1 r-l+1 r−l+1个数字组成的数,和 k k k从高到低的第 l l l位到第 r r r位组成的数的关系是小于、等于还是大于。转移就是从 f i , l + 1 , r , 0 / 1 / 2 f_{i,l+1,r,0/1/2} fi,l+1,r,0/1/2和 f i , l , r − 1 , 0 / 1 / 2 f_{i,l,r-1,0/1/2} fi,l,r−1,0/1/2转移到 f i , l , r , 0 / 1 / 2 f_{i,l,r,0/1/2} fi,l,r,0/1/2。
设 k k k的位数为 d d d,那么对于序列 a a a从 1 1 1到 i i i的答案 s u m i = f n , 1 , d , 0 + f n , 1 , d , 1 + ∑ j = 1 d − 1 ∑ p = 0 2 f n , 1 , j , p sum_i=f_{n,1,d,0}+f_{n,1,d,1}+\sum\limits_{j=1}^{d-1}\sum\limits_{p=0}^2f_{n,1,j,p} sumi=fn,1,d,0+fn,1,d,1+j=1∑d−1p=0∑2fn,1,j,p。前两项求的是位数等于 d d d且值小于等于 k k k的方案数,最后一项求的是位数小于 d d d的方案数。
设
a
n
s
l
i
,
j
ansl_{i,j}
ansli,j表示当
k
=
A
−
1
k=A-1
k=A−1时
a
i
,
a
i
+
1
…
,
a
j
a_{i},a_{i+1}\dots,a_{j}
ai,ai+1…,aj的答案,则
a
n
s
l
i
,
j
=
a
u
m
j
−
s
u
m
i
−
1
ansl_{i,j}=aum_j-sum_{i-1}
ansli,j=aumj−sumi−1。但实际上,这样算还麻烦了,我们其实并不需要求
s
u
m
i
sum_i
sumi。对于同一个
i
i
i,在枚举
j
j
j时继续用先前的
f
f
f数组,就能
O
(
n
2
log
2
A
)
O(n^2\log^2 A)
O(n2log2A)预处理出
a
n
s
l
i
,
j
ansl_{i,j}
ansli,j。
设
a
n
s
r
i
,
j
ansr_{i,j}
ansri,j表示当
k
=
B
k=B
k=B时
a
i
,
a
i
+
1
…
,
a
j
a_{i},a_{i+1}\dots,a_{j}
ai,ai+1…,aj的答案,则同理可以
O
(
n
2
log
2
B
)
O(n^2\log^2B)
O(n2log2B)预处理出
a
n
s
r
i
,
j
ansr_{i,j}
ansri,j。这样的话,查询就是
O
(
1
)
O(1)
O(1)的了。
总时间复杂度为 O ( n 2 log 2 B + q ) O(n^2\log^2B+q) O(n2log2B+q)。
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
int n,q,v1,a[305],v[25];
long long ansl[305][305],ansr[305][305],f[25][25][3];
long long L,R;
void dd(long long x){
v1=0;
while(x){
v[++v1]=x%10;x/=10;
}
reverse(v+1,v+v1+1);
}
int gt(int x,int y){
if(x<y) return 0;
else if(x==y) return 1;
else return 2;
}
int main()
{
scanf("%d%lld%lld",&n,&L,&R);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
dd(L-1);
for(int i=1;i<=n;i++){
memset(f,0,sizeof(f));
for(int j=i;j<=n;j++){
for(int l=1;l<=v1;l++){
for(int r=v1;r>l;r--){
if(a[j]>v[l]){
for(int k=0;k<=2;k++)
f[l][r][2]=(f[l][r][2]+f[l+1][r][k])%mod;
}
else if(a[j]==v[l]){
for(int k=0;k<=2;k++)
f[l][r][k]=(f[l][r][k]+f[l+1][r][k])%mod;
}
else{
for(int k=0;k<=2;k++)
f[l][r][0]=(f[l][r][0]+f[l+1][r][k])%mod;
}
f[l][r][2]=(f[l][r][2]+f[l][r-1][2])%mod;
f[l][r][gt(a[j],v[r])]=(f[l][r][gt(a[j],v[r])]+f[l][r-1][1])%mod;
f[l][r][0]=(f[l][r][0]+f[l][r-1][0])%mod;
}
}
for(int p=1;p<=v1;p++) f[p][p][gt(a[j],v[p])]=(f[p][p][gt(a[j],v[p])]+2)%mod;
ansl[i][j]=(ansl[i][j]+f[1][v1][0]+f[1][v1][1])%mod;
for(int p=1;p<v1;p++){
for(int k=0;k<=2;k++)
ansl[i][j]=(ansl[i][j]+f[1][p][k])%mod;
}
}
}
dd(R);
for(int i=1;i<=n;i++){
memset(f,0,sizeof(f));
for(int j=i;j<=n;j++){
for(int l=1;l<=v1;l++){
for(int r=v1;r>l;r--){
if(a[j]>v[l]){
for(int k=0;k<=2;k++)
f[l][r][2]=(f[l][r][2]+f[l+1][r][k])%mod;
}
else if(a[j]==v[l]){
for(int k=0;k<=2;k++)
f[l][r][k]=(f[l][r][k]+f[l+1][r][k])%mod;
}
else{
for(int k=0;k<=2;k++)
f[l][r][0]=(f[l][r][0]+f[l+1][r][k])%mod;
}
f[l][r][2]=(f[l][r][2]+f[l][r-1][2])%mod;
f[l][r][gt(a[j],v[r])]=(f[l][r][gt(a[j],v[r])]+f[l][r-1][1])%mod;
f[l][r][0]=(f[l][r][0]+f[l][r-1][0])%mod;
}
}
for(int p=1;p<=v1;p++) f[p][p][gt(a[j],v[p])]=(f[p][p][gt(a[j],v[p])]+2)%mod;
ansr[i][j]=(ansr[i][j]+f[1][v1][0]+f[1][v1][1])%mod;
for(int p=1;p<v1;p++){
for(int k=0;k<=2;k++)
ansr[i][j]=(ansr[i][j]+f[1][p][k])%mod;
}
}
}
scanf("%d",&q);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%lld\n",(ansr[l][r]-ansl[l][r]+mod)%mod);
}
return 0;
}