题意
有三个正整数 n , k , d n,k,d n,k,d,总共执行 k k k轮,每一轮可以选择 1 k 1~k 1 k里的任意一个数字,求最后一轮时,数字之和为n且存在一个数字大于d的情况。
解析
简单的dp,最终一个数字大于d是从0个数字大于0转移而来,因此建立两个数组进行转移即可。
状态转移方程
a
[
i
]
=
a
[
i
]
+
a
[
i
−
j
]
(
1
<
=
j
<
=
m
i
n
(
i
,
k
)
)
a[i]=a[i]+a[i-j] (1<=j<=min(i,k))
a[i]=a[i]+a[i−j](1<=j<=min(i,k))
b
[
i
]
=
b
[
i
]
+
a
[
i
−
j
]
+
b
[
i
−
j
]
(
j
>
=
d
,
1
<
=
j
<
=
m
i
n
(
i
,
k
)
)
b[i]=b[i]+a[i-j]+b[i-j] ( j>=d , 1<=j<=min(i,k))
b[i]=b[i]+a[i−j]+b[i−j](j>=d,1<=j<=min(i,k))
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
// 总和是n,至少有一条边大于等于d,k-tree
int a[105];//不符合条件的
int b[105];
void solve(){
ll n,k,d ;
scanf("%lld%lld%lld",&n,&k,&d);
a[0]=1;
for(int i=1;i<=n;i++){
//选择k个 i-j
for(int j=1;j<=i && j<=k;j++){
b[i]+=b[i-j];
b[i]%=mod;
if(j<d){
a[i]+=a[i-j];
a[i]%=mod;
}
else{
b[i]+=a[i-j];
b[i]%=mod;
}
}
}
cout<<b[n]<<endl;
}
int main(){
int t ;
t=1;
while(t--){
solve();
}
}