专栏文章
题解:P10259 [COCI 2023/2024 #5] Piratski kod
P10259题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min037hn
- 此快照首次捕获于
- 2025/12/01 18:22 3 个月前
- 此快照最后确认于
- 2025/12/01 18:22 3 个月前
思路分析
一看就差不多知道是 的 DP 了。接下来就是去推一下转移式一类的东西。
首先,一个很自然的想法是令 表示最后一段数字的海盗表示在 位置结束时的所有可能的正整数序列的和之和,并用 表示对应的不同的正整数序列的个数。
思考转移。显然 。其中 是转移系数。
我们思考一下这些转移系数是什么。对应到 和 的状态设计上,显然 表示的是长度为 的单个数字的海盗表示的方案数,而 则表示的是这些数字的海盗表示的原数字之和。
于是现在我们思考怎么快速的求出 。我们发现我们可以再进行一次 DP。具体的来说,我们令 表示长度为 的,最后一个数字为 的还没有结束的数字的海盗表示方案数,令 表示这些数字的海盗表示的原数字之和。
那么显然,只有在一个末尾为 的数字的海盗表示后面再加上一个 表示终止,才形成了一个完整的数字的海盗表示。于是 。
考虑 的转移式。非常显然,。其中 是题目中描述的斐波那契数。
于是我们首先通过 的递推式转移出 ,然后 转移出 和 的值。
代码如下:
CPP#include<bits/stdc++.h>
using namespace std;
#define int long long
constexpr bool online=0;
constexpr int mod=1e9+7;
int n,fi[5005],dv[5005][2],dc[5005][2],va[5005],vc[5005],anv[5005],anc[5005];
signed main(){
if(online)
freopen("piratski.in","r",stdin),
freopen("piratski.out","w",stdout);
ios::sync_with_stdio(0); fi[0]=fi[1]=1;
for(int i=2;i<=5000;++i) fi[i]=(fi[i-1]+fi[i-2])%mod;
dv[1][1]=dc[1][1]=dc[1][0]=1; dv[1][0]=0;
for(int i=2;i<=5000;++i){
va[i]=dv[i-1][1]; vc[i]=dc[i-1][1];
dv[i][1]=(dv[i-1][0]+dc[i-1][0]*fi[i])%mod;
dv[i][0]=(dv[i-1][1]+dv[i-1][0])%mod;
dc[i][0]=(dc[i-1][1]+dc[i-1][0])%mod;
dc[i][1]=dc[i-1][0];
}
anc[0]=1; cin>>n;
for(int i=2;i<=5000;++i)
for(int j=2;j<=i;++j)
anv[i]=(anv[i]+anv[i-j]*vc[j]+anc[i-j]*va[j])%mod,
anc[i]=(anc[i]+anc[i-j]*vc[j])%mod;
for(int i=n;i>=1;i--)
for(int j=1;j<=i;++j)
anv[i]=(anv[i]+anv[i-j]*fi[j+1])%mod;
for(int i=1;i<=n;++i) cout<<anv[i]<<" ";
cout<<endl;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...