概述
Gym - 101991K
题意
给定 N , K , L , R N,K,L,R N,K,L,R,构造一个长度为 N N N的数列,每个数在 [ L , R ] [L,R] [L,R]区间内,且和为3的倍数的区间恰好为 K K K个,求方案数。
题解
首先转换题意,和为3的倍数即和对3取模等于0,可以先考虑每个位置放0/1/2的方案数。
然后设计状态,设
d
p
[
n
]
[
k
]
[
x
]
[
y
]
[
z
]
[
0
/
1
/
2
]
dp[n][k][x][y][z][0/1/2]
dp[n][k][x][y][z][0/1/2],其中
n
n
n是构造数列长度、
k
k
k是和为3的倍数的区间数、
x
/
y
/
z
x/y/z
x/y/z 分别是和为
0
/
1
/
2
0/1/2
0/1/2 的前缀数量、最后是区间总和模3的值。此时状态数有
N
4
K
N^4K
N4K 那么大,显然是不可取的。通过计算可以发现,
n
=
x
+
y
+
z
n=x+y+z
n=x+y+z,且
k
=
[
x
⋅
(
x
+
1
)
+
y
⋅
(
y
−
1
)
+
z
⋅
(
z
−
1
)
]
/
2
k=[x·(x+1)+y·(y-1)+z·(z-1)]/2
k=[x⋅(x+1)+y⋅(y−1)+z⋅(z−1)]/2(前缀和相减得到区间和),因此前两维是不需要的。此时状态数仍然有
N
3
N^3
N3 那么多。通过上面的式子还可以发现,
x
/
y
/
z
x/y/z
x/y/z 并没有必要枚举到
N
N
N 那么大,因为
2
⋅
k
=
x
⋅
(
x
+
1
)
+
y
⋅
(
y
−
1
)
+
z
⋅
(
z
−
1
)
>
x
⋅
(
x
−
1
)
>
(
x
−
1
)
2
2·k=x·(x+1)+y·(y-1)+z·(z-1)>x·(x-1)>(x-1)^2
2⋅k=x⋅(x+1)+y⋅(y−1)+z⋅(z−1)>x⋅(x−1)>(x−1)2,即
x
<
2
⋅
k
+
1
<
143
x<sqrt{2·k}+1<143
x<2⋅k+1<143,
y
/
z
y/z
y/z同理。
之后考虑转移。首先求出
[
L
,
R
]
[L,R]
[L,R]区间内对3取模等于
0
/
1
/
2
0/1/2
0/1/2 的数字的数量,记为
c
[
0
/
1
/
2
]
c[0/1/2]
c[0/1/2]。这样就可以写出转移方程:
d
p
[
x
]
[
y
]
[
z
]
[
0
]
=
∑
w
=
0
2
d
p
[
x
−
1
]
[
y
]
[
z
]
[
w
]
⋅
c
[
(
0
−
w
)
%
3
]
dp[x][y][z][0]=sum_{w=0}^{2} dp[x-1][y][z][w]·c[(0-w)%3]
dp[x][y][z][0]=w=0∑2dp[x−1][y][z][w]⋅c[(0−w)%3]
d
p
[
x
]
[
y
]
[
z
]
[
1
]
=
∑
w
=
0
2
d
p
[
x
]
[
y
−
1
]
[
z
]
[
w
]
⋅
c
[
(
1
−
w
)
%
3
]
dp[x][y][z][1]=sum_{w=0}^{2} dp[x][y-1][z][w]·c[(1-w)%3]
dp[x][y][z][1]=w=0∑2dp[x][y−1][z][w]⋅c[(1−w)%3]
d
p
[
x
]
[
y
]
[
z
]
[
2
]
=
∑
w
=
0
2
d
p
[
x
]
[
y
]
[
z
−
1
]
[
w
]
⋅
c
[
(
2
−
w
)
%
3
]
dp[x][y][z][2]=sum_{w=0}^{2} dp[x][y][z-1][w]·c[(2-w)%3]
dp[x][y][z][2]=w=0∑2dp[x][y][z−1][w]⋅c[(2−w)%3]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e9+7;
ll d[160][160][160][3];
int main(){
ifstream fin("khoshaf.in");
int T,n,k,l,r;
fin>>T;
while(T--){
fin>>n>>k>>l>>r;
if(n>400){
cout<<"0n";
continue;
}
int c[3]={(r-l+1)/3,(r-l+1)/3,(r-l+1)/3};
if(l%3==r%3)c[l%3]++;
if((l+1)%3==r%3)c[l%3]++,c[r%3]++;
ll ans=0;
memset(d,0,sizeof d);
d[0][0][0][0]=1;
for(int x=0;x<150;x++)if(x<=n){
for(int y=0;y<150;y++)if(x+y<=n){
for(int z=0;z<150;z++)if(x+y+z<=n){
for(int w=0;w<3;w++){
auto &dx=d[x][y][z][w];
dx%=M;
d[x+1][y][z][0]+=dx*c[(3-w)%3];
d[x][y+1][z][1]+=dx*c[(4-w)%3];
d[x][y][z+1][2]+=dx*c[(5-w)%3];
if(x+y+z==n && x*(x+1)+y*(y-1)+z*(z-1)==k*2)
ans+=dx;
}
}
}
}
cout<<ans%M<<'n';
}
return 0;
}
最后
以上就是坚定裙子为你收集整理的【Gym - 101991K】Khoshaf(动态规划)的全部内容,希望文章能够帮你解决【Gym - 101991K】Khoshaf(动态规划)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复