[COCI2015-2016#6] PAROVI(区间线段覆盖方案数)
written on 2022-07-12
然后手模一下一些数据,很容易可以将这些数对转化为一条条线段,那么根据题意,答案即为:从这些线段中任选若干条使得它们能覆盖整个区间的方案数。
经计算机测试,线段数最多有
-
状态设计:动态规划设计状态的第一步是确定阶段,这一题的阶段很显然就是目前已选择的线段数量。但是仅有这一维是无法转移的,那么事实上对于区间线段覆盖的题目,将值域作为第二维往往是有效的处理方案。因此对于这一题,我们设
表示目前已经处理了前 条线段,值域为 的部分已经被完全覆盖的方案数。 -
转移方程:考虑一个阶段中,一条线段有选与不选两种决策。若不选,那么直接转移,即
;若选,那么原先在这条线段上的所有值域均可以转移,即 。
观察式子,为了保证没有后效性,我们应当先将所有线段按右端点递增的顺序排序。
当然转移方程还存在问题。对于选取这条线段的情况,还存在这条线段对转移不存在贡献的那部分!因此,转移中容易被忽略的一个式子是:
考试的时候想到要用动态规划,但是被状态的第二维设计给卡住了,说明我还是太菜了,基础太烂,题目做得太少。另外还有一点总结一下,就是转移时最好明确三种方式:
-
不选的情况。
-
选了有贡献的情况。
-
选了也没有贡献的情况。
要不然很容易导致转移错误。
#include<bits/stdc++.h>
#define N 130
using namespace std;
const int mod=1e9;
int n,tot;
struct F{int x,y;}a[N];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
bool cmp(F a,F b){return a.y<b.y;}
int f[N][25];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) if(gcd(i,j)==1) a[++tot]=(F){i,j};
sort(a+1,a+1+tot,cmp);
f[0][1]=1;
for(int i=1;i<=tot;i++)
{
//不选这条线段
for(int j=1;j<=n;j++) f[i][j]=f[i-1][j];
//选了这条线段
//有贡献的部分
for(int j=a[i].x;j<=a[i].y;j++) f[i][a[i].y]=(f[i][a[i].y]+f[i-1][j])%mod;
//不贡献的部分
for(int j=1;j<a[i].x;j++) f[i][j]=(f[i][j]+f[i-1][j])%mod;
}
printf("%d\n",f[tot][n]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】