@atcoder - AGC035E@ Develop
@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的更多相关文章
- 【AtCoder】AtCoder Grand Contest 035 解题报告
点此进入比赛 \(A\):XOR Circle(点此看题面) 大致题意: 给你\(n\)个数,问是否能将它们摆成一个环,使得环上每个位置都是其相邻两个位置上值的异或值. 先不考虑\(0\),我们假设环 ...
- AtCoder Grand Contest 035
Preface Atcoder的题都好劲啊,都是我做不动的计数与构造 就当锻炼自己的思维能力了(基本都是bzt教的) A - XOR Circle bzt说这题数据太水了只要判一下所有数异或值是否为\ ...
- Codeforces & Atcoder神仙题做题记录
鉴于Codeforces和atcoder上有很多神题,即使发呆了一整节数学课也是肝不出来,所以就记录一下. AGC033B LRUD Game 只要横坐标或者纵坐标超出范围就可以,所以我们只用看其中一 ...
- PLSQL Develop PlugIn 之脚本自动匹配补全工具CnPlugin
插件位置:百度云 -- 开发工具空间 -- CnPlugin CnPlugin 支持PL/sql Developer 7.0以上版本,它可以根据 关键字+tab/space 来触发代码补全,而关键字. ...
- How to Develop blade and soul Skills
How to Develop Skills Each skill can be improved for variation effects. Some will boost more strengt ...
- Server Develop (七) Linux 守护进程
守护进程 守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装 ...
- android network develop(1)----doing network background
Develop network with HttpURLConnection & HttpClient. HttpURLConnection is lightweight with Http ...
- Gitlab的develop角色的人没有权限无法提交的问题解决方案
问题 事情是这样的,最近跟几位同事搞一些东西,打算在Gitlab上建一个仓库,然后协同开发. 我建好仓库,将其他几位同事添加进来,角色分配为Develop. 之后提交初始代码到master分支后,他们 ...
- 国内android帮助文档镜像网站---http://wear.techbrood.com/develop/index.html
http://wear.techbrood.com/develop/index.html
随机推荐
- 在网站制作过程中发现的block和inline-block不同。
inline-block,简单来说就是在CSS中通过display:inline-block对一个对象指定inline-block属性,可以将对象呈递为内联对象,但是对象的内容作为块对象呈递.有时既希 ...
- js的模块化写法
记得前两天自己写一个动画首页,动画很复杂,我用的fullpage虽然相对比较简单,但是每个页面的animation各有差异,需要相对控制,估计有上千行的js代码,写的心情乱糟糟的. 如何让代码量巨大, ...
- 深度优先搜索(Depth-First-Search)精髓
引例:迷宫问题 首先我们来想象一只老鼠,在一座不见天日的迷宫内,老鼠在入口处进去,要从出口出来.那老鼠会怎么走?当然可以是这样的:老鼠如果遇到直路,就一直往前走,如果遇到分叉路口,就任意选择其中的一条 ...
- 关于springmvc 只能在index.jsp页面显示图片的处理办法jsp页面无法显示图片
首先,已经配置好了mvc对静态资源的处理 只有index,jsp可以显示图片 其他页面同样的代码则不显示 后来折腾了半天,发现 index是static的父目录的级别文件 可以向下访问 但是其他的js ...
- [待验证]使用hibernate注解忘记引入mapping导致的问题
这个问题好像是注解主键的时候,主键没有设置为int型,我设置了个string(想直接用uuid)导致的 后来学习了一下,这个主键的注解,生成策略有很多种,换成别的,就可以使用string类型 编译报错 ...
- 洛谷 P1004 方格取数 【多线程DP/四维DP/】
题目描述(https://www.luogu.org/problemnew/show/1004) 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0. ...
- db link的查看创建与删除 1
1.查看dblink select owner,object_name from dba_objects where object_type='DATABASE LINK'; 或者 select * ...
- Promise对象和async函数
Promise对象 //1开始 function fna(){ console.log('1开始'); var p = new Promise(function(resolve, reject){ / ...
- 【教程】5分钟在PAI算法市场发布自定义算法
概述 在人工智能领域存在这样的现象,很多用户有人工智能的需求,但是没有相关的技术能力.另外有一些人工智能专家空有一身武艺,但是找不到需求方.这意味着在需求和技术之间需要一种连接作为纽带. 今天PAI正 ...
- hihocoder1317 :搜索四·跳舞链
精确覆盖问题是指对于给定的一个由0-1组成的矩阵,是否能找到一个行的集合,使得集合中每一列都恰好包含一个1. //Achen #include<algorithm> #include< ...