CTH: 谁帮我切开这个蛋糕???
f[i]=n+1∑j=i+1f[j]
至于为什么循环到 n+1 ,循环到第 j 位时,我们要把这一位与后面的若干位(也许没有)划分到一起,当前位置的数可以和后面所有的数划分到一起,那么临界就是搜索第 n+1 位而非第 n 位。
当 bit[i] 为 0 时,有
f[i]=f[i+1]
所以直接状态转移即可,或者 dfs 也行(不过都是 O(n2) 的新的数据范围可以卡)。
DFS
#define yhl 0
#include"bits/stdc++.h"
using namespace std;
const int N=3e3+10,p=998244353;
int f[N],n,bit[N];
char ch[N];
int dfs(int pos){
if(f[pos]!=-1)return f[pos];
if(pos>=n)return 1;
int ans=0;
if(ch[pos]=='1')for(int j=pos+1;j<=n+1;j++)ans=(ans+dfs(j))%p;
else ans=dfs(pos+1);
return f[pos]=ans;
}
int main(){
memset(f,-1,sizeof f);
scanf("%d",&n);int nl=n;
scanf("%s",ch+1);
printf("%d",dfs(1));
return yhl;
}
动归
#define yhl 0
#include"bits/stdc++.h"
using namespace std;
const int N=3e3+10,p=998244353;
int f[N],n;
char ch[N];
int main(){
scanf("%d",&n);scanf("%s",ch+1);
f[n+1]=1;
for(int i=n;i>=1;i--){
if(ch[i]=='1')for(int j=i+1;j<=n+1;j++)f[i]=(f[i]+f[j])%p;
else f[i]=f[i+1];
}
printf("%d",f[1]);
return yhl;
}
其实看了动归代码我们可以发现转移时实际上是在求前缀和,直接拿数组维护一下即可,实际上我们并不需要定义一个数组,直接拿一个变量存即可,请读者自行理解。
所以最后 O(n) 的代码就出来了(doge)
点击查看代码
#define yhl 0
#include"bits/stdc++.h"
using namespace std;
const int N=3e3+10,p=998244353;
int ans=1,s=1,n;
char ch[N];
int main(){
scanf("%d",&n);
scanf("%s",ch+1);
for(int i=n;i>=1;i--){
if(ch[i]=='1')ans=s;
s=(s+ans)%p;
}
printf("%d",ans);
return yhl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?