CF2018F1~3 Solution
相当于计数如下正整数序列
,
我们可以考虑枚举
那么就只需要考虑第三个条件了,同时需要注意
感觉可以按值大小依次填数唉。
如果按照原题目的想法,也可以看作答案区间
哦,要计算所有的
那相当于是我可以考虑容斥,也就是我计算出
那么我们考虑如何求出
考虑使用这样一种策略:除非右侧有一个点需要立刻向右走,否则就向左走,这样可以确保一个起点生成的方案唯一。
我们将一个方案描述为
根据
定义
初始值显然是
考虑转移。
注意到如果你从
而且如果你填了
同时每一次扩展后导致长度增加,那么也有可能会导致又必须往右走。
所以可以设计出一个
另外,对于一个合法的
所以会有一个
那么容斥下就是
另外
int sol(int L,int R){
for(int i=1;i<=n;++i)for(int j=i;j<=n;++j)f[i][j][0]=f[i][j][1]=0;
for(int i=L;i<=R;++i)f[i][i][0]=f[i][i][1]=n+1-max(R-i+1,i-L+1);
for(int len=2;len<=n;++len){
for(int l=1,r=len;r<=n;++l,++r){
int vl=(n+1-Max({R-l+1,l-L+1,len}));
int vr=(n+1-Max({R-r+1,r-L+1,len}));
f[l][r][0]=f[l+1][r][0]*vl%p;
if(len>=max(R-r+1,r-L+1))(f[l][r][0]+=f[l][r-1][1])%=p;
f[l][r][1]=(f[l+1][r][0]*vl%p+f[l][r-1][1]*vr%p)%p;
}
}
// cout<<f[1][n][0]<<"\n";
return f[1][n][0];
}
写出代码后可以发现,对于相同长度的区间,
也即,我们只处理
for(int len=1;len<=n;++len){
sol(n-len+1,n);
for(int l=1,r=len;r<=n;++r,++l)ans[l][r]=f[l][n+l-1][0]*inv[len]%p;
}
注意到 F3 需要一个
我们注意到 一个方案中,第一次往右走的时刻就确定了左端点,当然反过来也是一样的。
所以如果我们可以考虑求一个固定左端点的DP。
也即如果我们可以求得
我们对于每个
可以运用上面那个技巧将
这样就做到了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!