@description@

给定初始集合为 1 ~ N 的全集,并给定一个 K。

每次对于当前集合 S,你可以选择 S 中的一个元素 x,并将 x 从 S 中删除。

假如 x - 2 在 1 ~ N 的范围内且不在集合 S 中,在 S 中加入 x - 2。

假如 x + K 在 1 ~ N 的范围内且不在集合 S 中,在 S 中加入 x + K。

求最后可以得到的不同集合数量 mod M。

Constraints

1≤K≤N≤150, 108≤M≤109

Input

输入格式如下:

N K M

Output

输出不同集合数量 mod M。

Sample Input 1

3 1 998244353

Sample Output 1

7

@solution@

考虑假如 x 与 x-2 最后都要被删除,肯定应该先删 x 再删 x-2(先删 x-2 的话,再删 x 就又多出来一个 x-2)。

那么我们连边 x -> x-2,x -> x+K,表示 x 比 x-2, x+K 先删。

最后如果要求删除的点形成一个环,肯定无解。否则我们按照拓扑序来删必然是一个合法方案。

那么相当于对于这样一个图,有多少点集满足点集内的点不形成环。

考虑与 K 无关的那些边,会连成 1 <- 3 <- ... 与 2 <- 4 <- ... 两条链,一条奇数,一条偶数。

接下来将 K 分奇偶讨论,因为 K 是偶数时 x -> x+K 必然是在奇偶内部连边,而 K 为奇数时可以跨奇偶连边。

当 K 为偶数时,我们要避免 a -> a-2 -> ... a-K -> a 这样的环,其实就是不能选择超过 K/2 + 1 个连续点。

这个随便怎么 dp 都可以。

当 K 为奇数时。注意到最小环必然恰好经过 2 条 K 边(0,1 显然,> 2 可以缩成 2 条)。

我们先将图写成类似以下形式(假设 K = 3):

其实就是对于每个奇数 x,将 x 与 x + K 放在同一层。

这样有什么好处呢?注意到环的形式一定为 a -> a-2 -> ... b-K -> b -> b-2 -> ... a-K -> a(假设 a 为奇数),对应到图上即从 a 开始往上走到某一点 b-K,再往右走到 b,再往上走到 a-K 的地方。

等价地说,假如这样一条往上 + 往右 + 往上的路径包含 > K + 1 个点,就会形成环。

注意到这样一条路径没有往下的选择,所以我们就可以从上到下 dp。

定义 dp(i, j, k) 表示前 i 层,往上 + 往右 + 往上的路径包含 j 个点,右边偶数的链对应往上的点连续选中了 k 个。

k 这一维是为了方便我们得到新的 j(可能在 i 这个点直接往右走)。

注意往上 + 往右 + 往上,两个往上可以缩减成一个点,但必须要有往右的过程。

@accepted code@

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 150;
int N, K, M;
int add(int a, int b) {return (a + b)%M;}
int mul(int a, int b) {return 1LL*a*b%M;}
int f[MAXN + 5][MAXN + 5];
void solve1() {
K /= 2, f[0][0] = 1;
for(int i=1;i<=N;i++) {
for(int j=0;j<=K;j++)
f[i][0] = add(f[i][0], f[i-1][j]);
for(int j=0;j<K;j++)
f[i][j+1] = add(f[i][j+1], f[i-1][j]);
}
int ans1 = 0, ans2 = 0;
for(int i=0;i<=K;i++)
ans1 = add(ans1, f[N/2][i]);
for(int i=0;i<=K;i++)
ans2 = add(ans2, f[(N+1)/2][i]);
printf("%d\n", mul(ans1, ans2));
}
int g[2*MAXN + 5][MAXN + 5][MAXN + 5];
void solve2() {
int p; g[0][0][0] = 1;
for(int i=2;i-K<=N;i+=2) {
for(int j=0;j<=N;j++)
for(int k=0;k<=K+1;k++)
g[i][0][0] = add(g[i][0][0], g[i-2][j][k]);
if( i <= N ) {
for(int j=0;j<=N;j++)
for(int k=0;k<=K+1;k++)
g[i][j+1][0] = add(g[i][j+1][0], g[i-2][j][k]);
}
if( i - K >= 1 ) {
for(int j=0;j<=N;j++) {
for(int k=1;k<=K;k++)
g[i][0][k+1] = add(g[i][0][k+1], g[i-2][j][k]);
g[i][0][0] = add(g[i][0][0], g[i-2][j][0]);
}
}
if( i <= N && i - K >= 1 ) {
for(int j=0;j<=N;j++)
for(int k=0;max(k,j+1)<=K;k++)
g[i][j+1][max(k+1,j+2)] = add(g[i][j+1][max(k+1,j+2)], g[i-2][j][k]);
}
p = i;
}
int ans = 0;
for(int j=0;j<=N;j++)
for(int k=0;k<=K+1;k++)
ans = add(ans, g[p][j][k]);
printf("%d\n", ans);
}
int main() {
scanf("%d%d%d", &N, &K, &M);
if( K % 2 == 0 ) solve1();
else solve2();
}

@details@

感觉 AGC 好像很喜欢出这种状态定义比较抽象,但是状态转移非常简单的 dp 题。

比如 AGC039E,或者说 AGC037D 都是这种类型的 dp。

你以为你绕了半天写出来的长代码就是正解了?

拜托,正解根本不足 100 行.jpg。

但是做了这么多 AGC 的 dp 题还是不会 QAQ。

@atcoder - AGC035E@ Develop的更多相关文章

  1. 【AtCoder】AtCoder Grand Contest 035 解题报告

    点此进入比赛 \(A\):XOR Circle(点此看题面) 大致题意: 给你\(n\)个数,问是否能将它们摆成一个环,使得环上每个位置都是其相邻两个位置上值的异或值. 先不考虑\(0\),我们假设环 ...

  2. AtCoder Grand Contest 035

    Preface Atcoder的题都好劲啊,都是我做不动的计数与构造 就当锻炼自己的思维能力了(基本都是bzt教的) A - XOR Circle bzt说这题数据太水了只要判一下所有数异或值是否为\ ...

  3. Codeforces & Atcoder神仙题做题记录

    鉴于Codeforces和atcoder上有很多神题,即使发呆了一整节数学课也是肝不出来,所以就记录一下. AGC033B LRUD Game 只要横坐标或者纵坐标超出范围就可以,所以我们只用看其中一 ...

  4. PLSQL Develop PlugIn 之脚本自动匹配补全工具CnPlugin

    插件位置:百度云 -- 开发工具空间 -- CnPlugin CnPlugin 支持PL/sql Developer 7.0以上版本,它可以根据 关键字+tab/space 来触发代码补全,而关键字. ...

  5. How to Develop blade and soul Skills

    How to Develop Skills Each skill can be improved for variation effects. Some will boost more strengt ...

  6. Server Develop (七) Linux 守护进程

    守护进程 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装 ...

  7. android network develop(1)----doing network background

    Develop network with HttpURLConnection & HttpClient. HttpURLConnection  is lightweight with Http ...

  8. Gitlab的develop角色的人没有权限无法提交的问题解决方案

    问题 事情是这样的,最近跟几位同事搞一些东西,打算在Gitlab上建一个仓库,然后协同开发. 我建好仓库,将其他几位同事添加进来,角色分配为Develop. 之后提交初始代码到master分支后,他们 ...

  9. 国内android帮助文档镜像网站---http://wear.techbrood.com/develop/index.html

    http://wear.techbrood.com/develop/index.html

随机推荐

  1. chrome屏蔽https广告

    “设置” -> “高级” -> 系统/“打开代理设置” -> “安全” -> “受限站点” -> “添加” 好了

  2. jeecms怎么修改后台访问路径?

    1,修改后台访问路径: 如:http://localhost:8080/jeeadmin/jeecms/login.do 改:http://localhost:8080/hailou/index.do ...

  3. oracle-表空间-用户-角色-权限

    概要图 概要图 一 表空间 1.1创建表空间 --问题:创建一个名为hp的表空间,指定数据文件为hp.dbf,大小为10m. create tablespace hp datafile 'C:\app ...

  4. ubuntu和win10设置双显示器

    ubuntu:最右上角那个图标,点开找到系统设置,系统设置中找到“显示”中,在其中可以调节双屏显示或者只显示一个屏,图等会补... win10:现在是ubuntu系统所以操作忘记了写不出来,等下换系统 ...

  5. Unity 同一Text文本修改不同的字体大小和字体颜色

    类似Html,在color和size对应的<>str</>中,就能修改str的相关属性, 下面的代码就是把time改为字体颜色为红色,大小为40: 而前面的"Time ...

  6. javaScript中的事件对象event是怎样

    事件对象event,每当一个事件被触发的时候,就会随之产恒一个事件对象event,该对象中主要包含了关于该事件的基本属性,事件类型type(click.dbclick等值).目标元素target(我的 ...

  7. 用 Python 写一个 NoSQL 数据库Python

    NoSQL 这个词在近些年正变得随处可见. 但是到底 “NoSQL” 指的是什么? 它是如何并且为什么这么有用? 在本文, 我们将会通过纯 Python (我比较喜欢叫它, “轻结构化的伪代码”) 写 ...

  8. 001. 注释过的boot.s

    从网上搜罗一个很详细注释的boot.s版本,加了小小一点点自己的理解,不太多. 用 as86, ld86 可以编译,   ubuntu下可以通过 apt install bin86 来安装好像. ; ...

  9. 当inline-block和text-indent遇到IE6,IE7

    在实际应用中,考虑到seo,很多button,icon都要用到inline-block和text-indent来处理,例如: <a href="#" class=" ...

  10. Mybatis - plus 配置与运用

    Mybatis - plus mybatis-plus 官方文档  1.配置 引入对应的文件包,spring boot + mybatis 需添加依赖文件如下: <dependencies> ...