预设型 DP
预设型 DP
《美好的一天》--青春学概论
한 잔 술에 취해 잠긴 목엔
沉醉于一杯酒
갈라지는 목소린 다시
带着沙哑的嗓音
두 잔 자기 전엔 기분 좋음
入睡前饮下第二杯让心情愉悦
알 수 없는 세상에 빠져
陷入不可预知的世界
세 잔 또 네 잔 술에 빠진
又沉醉于第三杯第四杯
세상과 취해가는 사람들
这个世界还有酒醉的人们
다시 또다시 기분 좋음
再一次变得心情愉悦
다 노래를 부른다
大家放声高歌
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
목소리는 다시
再次高歌
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
솔직히 우리는
说实话
친구 그 이상도
我们的关系
이하도 아닌데
似友情却非友情
가끔 네가
偶尔会觉得
너무 예뻐 보여
你很美丽
이게 말이 돼
这像话吗
특히 오늘 같은
特别是在今天
날이면 더더욱
这样的日子
지금 네가 쳐다보고
你现在正在
있는 손거울
看的镜子
그게 내 얼굴이었으면 하는
如果是我的脸就好了
말도 안 되는 생각
有着这样不像话的想法
널 자기라고 부를 날이 올까
会有一天我能叫你亲爱的吗
언젠가 미안 취한 것 같아 나
会是什么时候呢 对不起我好像喝醉了
그래도 좋은 날이니까
即使这样也是好日子
뭐 이 정도는 괜찮잖아
应该没有关系吧
한 잔 술이 들어가니까
饮下一杯酒
두 잔 새벽 세 시잖아
第二杯已经到了凌晨三点
괜찮아 첫차 뜰 때까지
没关系 直到清晨来临
같이 있어 줄게
我会一直
네 곁에
在你左右
하루 밤 새워 마신 술이
熬夜饮下的酒
이틀 휘청거리게 해도
即使会让第二天眩晕
괜찮아 기대 내 어깨에
没关系 靠在我的肩膀上
난 그림자처럼
我会像影子般
말없이 항상 네 옆에
默默无语 一直陪伴你身边
세 잔 또 네 잔 술에 빠진
又沉醉于第三杯第四杯
세상과 취해가는 사람들
这个世界还有酒醉的人
다시 또다시 기분 좋음
再一次变得心情愉悦
다 노래를 부른다
大家放声高歌
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
목소리는 다시
再次高歌
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
오늘의 주인공은 너
你是今天的主角
생일 축하해
生日快乐
동시에 코 앞까지 온
也祝贺你
입대를 축하해
近在眼前的入伍日子
놀리는 건 아냐
不是开玩笑
나도 곧 갈텐데 뭐
我也马上就要去了
신경 쓰지 말고 임마
不要想太多 小子
빈 잔이나 채워
将空杯斟满酒
넌 항상 되고 싶어 했잖아
你不是一直想要成为
진짜 사나이
真正的男人吗
이젠 그 시간이 온 거지
现在这一天来了
나의 둘도 없는 친구 놈인
我独一无二的朋友
너에게도 말이야
你也是一样
오늘은 우리들끼리
今天我们要
끝까지 가는 날이야
一直喝到最后
한 잔 술이 들어가니까
饮下一杯酒
두 잔 새벽 세 시잖아
第二杯已经到了凌晨三点
우리는 아직 젊고
我们正年轻
이 새벽은 길어
这个深夜太长
하나 걱정이 있다면
仅有的担心是
네가 조금 취했다는 정도
你已经微微醉了
하루 밤 새워 마신 술이
熬夜饮下的酒
이틀 휘청거리게 해도
即使会让第二天眩晕
우리는 아직 젊고
我们正年轻
그건 축복이지
那就是祝福
이 노래는 우리를
这是为我们
위한 곡이지
唱的歌
세상은 취해 돌고
在我的世界沉醉旋转
내 두 눈은 감기고
闭上我的双眼
술에 취해 조금 어지럽지만
虽然醉酒让我有些眩晕
이 기분이 난 좋아
但我喜欢这样的心情
네가 생각나는 밤
想起你的夜里
나는 다시 노래를 부른다
我再一次歌唱
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
목소리는 다시
再次高歌
라라랄라랄라라
啦~
라라랄라랄라라
啦~
라라랄라랄라라
啦~
목소리는 다시 꼬이긴 해도
再次高歌 就算跑调
하나도 안 이상해 괜찮아
没关系 一点也不奇怪
오늘만큼은
今天这样的日子
네가 저녁때 뭘 먹었는지
即使让我看到你晚上吃的什么
보여줘도 괜찮아
也没关系
오늘만큼은
今夜
집에 가는 길에
回家的路
자꾸만 춤을 춰도 괜찮아
就算跳舞也没关系
오늘만큼은
像今天
함께 있으면
在一起的日子
좋은 사람들과의 기분 좋은 날
和美好的人一起度过的让人心情愉悦的日子
오늘만큼은
今天这样
한 잔 술에 취해 잠긴 목엔
沉醉于一杯酒
갈라지는 목소린 다시
带着沙哑的嗓音
두 잔 자기 전엔 기분 좋음
入睡前饮下第二杯让心情愉悦
다 노래를 부른다
大家放声高歌
前言
一种非常神奇的 \(DP\) 方式,可以处理排列计数问题。
例题
DP 搬运工1
题意:给你 \(n,K\) ,求有多少个 \(1\) 到 \(n\) 的排列,满足相邻两个数的 \(\max\) 的和不超过 \(K\) 。答案对 \(998244353\) 取模。
\(n \le 50 , K \le n^2\)
设 \(dp_{i , j , k}\) 表示 前 \(i\) 个数,分成 \(j\) 个连续段,和为 \(k\) 的个数。
我们从大往小里加,保证了每次增加的答案为 \(i\) .
无非分成三种情况:
- \(i\) 自成一个连续段 : 现在有 \(j - 1\) 个连续段,新加的有 \(j\) 种可能性,因此:
\]
- \(i\) 并在一个连续段里,即变为一个连续段的两端。 \(j\) 个连续段,显然有 \(2j\) 种选法,因此:
\]
- \(i\) 连起来两个连续段,最后 \(j\) 段,之前就是 \(j + 1\) 段,那么就是 \(j\) 个空,因此:
\]
于是我们就得到了 \(dp_{i , j , k}\) .
TexCode
CODE
#include <bits/stdc++.h>
#ifdef Using_Fread
char buf[1 << 20] , *p1 , *p2 ;
#define getchar() ((p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 1 << 20 , stdin) , p1 == p2)) ? EOF : *p1 ++)
#endif
#ifdef linux
#define getchar getchar_unlocked
#define putchar putchar_unlocked
#endif
using namespace std ;
typedef long long ll ;
const int N = 52 ;
const int mod = 998244353 ;
namespace Fast_IO {
inline ll read() {
ll x = 0 , f = 1 ;
char c = getchar() ;
while (c < '0' || c > '9') {
c = getchar() ;
}
while (c >= '0' && c <= '9') {
x = x * 10 + c - '0' ;
c = getchar() ;
}
return x * f ;
}
void write(ll x) {
if (x / 10) write(x / 10) ;
putchar(x % 10 + '0') ;
}
} using namespace Fast_IO ;
int n , K ;
int dp[N][N][N * N] ;
signed main() {
#ifdef LOCAL
freopen("1.in" , "r" , stdin) ;
freopen("1.out" , "w" , stdout) ;
#endif
n = read() , K = read() ;
if (n == 1) {
cout << 1 ;
return 0 ;
}
dp[1][1][0] = 1 ; ll val = 1 ;
for (int i = 2 ; i <= n ; ++ i) {
dp[i][i][0] = (val * i) % mod ; val = (val * i) % mod ;
for (int j = 1 ; j < i ; ++ j) {
for (int k = 1 ; k <= i * i ; ++ k) {
dp[i][j][k] = ((ll)dp[i - 1][j - 1][k] * (ll)j) % mod ;
dp[i][j][k] = (dp[i][j][k] + (dp[i - 1][j][k - i] * ((2ll * (ll)j) % mod)) % mod) % mod ;
if (k >= 2 * i) dp[i][j][k] = (dp[i][j][k] + (ll)((ll)dp[i - 1][j + 1][k - 2 * i] * (ll)j) % mod) % mod ;
}
}
}
ll ans = 0 ;
for (int i = 1 ; i <= K ; ++ i) {
ans = (dp[n][1][i] + ans) % mod ;
}
cout << ans << '\n' ;
}
[JOI Open 2016] 摩天大楼
译自 JOI Open 2016 T3 「高層ビル街 / Skyscraper」
题目描述
将互不相同的 \(N\) 个整数 \(A_1, A_2, \cdots, A_N\) 按照一定顺序排列。
假设排列为 \(f_1, f_2, \cdots, f_N\),要求:\(| f_1 - f_2| + | f_2 - f_3| + \cdots + | f_{N-1} - f_N| \leq L\)。
求满足题意的排列的方案数对 \(10^9+7\) 取模后的结果。
\(N \le 100 , L \le 1000 , A_i \le 1000 (i \in [1 , n])\)
这是好题
先考虑一下 \(O(n^2\sum\limits a_i)\) 的做法:
我们为了处理掉绝对值号,直接将 \(A_i\) 从大到小排序。
如果我们不进行连续段合并,就是说只考虑往两端加的情况,显然是一个钩子状的。
图:
(反正类似吧)
然后我们对于这样的段来说,其答案显然为 \(left + right - 2mid\)
( \(left\) 指最左端值, \(right\) 指最右段值, \(mid\) 指中间段最小的那个数 )
然后如果两个钩子合并的话,图:
我们就发现中间那个最高的变成左右两个的左端或右端。
那总答案 \(\Delta\) 为 \(2new - left_{right} - right_{left}\)
我们发现只要不是最左端或最右端,那么都会经历一个这样的过程,因此在我们 \(DP\) 的时候,只将区间最左和区间最右的特殊考虑。
具体的,设 \(dp_{i , j , k , d}\) 表示前 \(i\) 个, \(j\) 段 , 答案为 \(k\) , 拥有 \(d\) 个端点( \(1\) 或 \(n\) )。
那如果是合并段:
\]
至于为什么从 \(k-2a_i\) 转移来,就是为了上图中可能的减法(我们不知道那俩数是啥)准备的,非极端点不加入转移。
若是新加段且不为端点:
\]
\(a_i\) 将是 \(a_i\) 所在钩子的最小值, (上面不是算出 \(-2mid\) 吗)。
若是新加段并是端点:
\]
端点只有左右两种情况了吧。为什么从 \(k + a_i\) 转移来是因为其与某个 \(left\) 或 \(right\) 重合,需特殊处理。
若是并在某段两边,且不为端点:
\]
若是并在某段两边,且为端点:
\]
然后我们发现这个 \(DP\) 第三维是要处理到 \(\sum a_i\) 的,因为既有加又有减。
所以时间复杂度是 \(O(n^2 \sum a_i)\) 的,寄了。
然后考虑一下优化哈。有这么个东西叫提前处理答案。
对于一个差分 \(a_{i + 1} - a_i\) 他的贡献。
我们发现对于 \(a_i - a_j (i > j)\) 来说,我们知道这个:
\]
那么只有左右 \(i < k \le j\) 时 \(a_k - a_{k - 1}\) 才被计算。
那么就是说在当 \(a_{i + 1}\) 加入时:
现在共有 \(j\) 个段吧,那么这 \(j\) 个段里每个数都是小于 \(a_{i + 1}\) 的。
那么加入 \(a_{i + 1}\) 以后,很多数并在了 \(j\) 个段的左右两端。
假设段 \(k\) 在左端未处理 \(a_{i + 1}\) 前数为 \(x\) , 第一个在处理完 \(a_{i + 1}\) 后数为 \(y\) 。
显然 \(y > a_{i + 1} > x\) 。
那么 \(y - x\) 的值就有 \(a_{i + 1} - a_i\) 的一份贡献。
再往后,新并在 \(y\) 左的值就不满足条件了。同理, \(k\) 右端第一个新并上的值一样,所有端包括 \(a_{i + 1}\) 所处的端也一样。
那么我们就发现共有 \(2j\) 个位置是符合条件的,是能被贡献上的。当然还要考虑左右极端点,设已有个数为 \(d\) , 所以本差分贡献为 \((2j - d) \times (a_{i + 1} - a_i)\) ( \(j\) 是处理前的段的数量 ) 。
然后就可以得到式子了。 \(DP\) 设计不变,只要将所有的 \(k\) 加减什么数全部改成 \(k_2 =(2j - d) \times (a_{i + 1} - a_i)\) 就可以了。
如果目前的 \(k_2\) 超过 \(L\) 直接不算弃了就行,时间复杂度 \(O(n^2L)\) 。
#include <bits/stdc++.h>
using namespace std ;
typedef long long ll ;
const int N = 101 ;
const int M = 1010 ;
const int mod = 1e9 + 7 ;
int n , m , a[N] ;
int dp[N][N][M][3] ;
signed main() {
ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0) ;
cin >> n >> m ;
if (n == 1) { // 特判 n = 1
cout << 1 ; return 0 ;
}
for (int i = 1 ; i <= n ; ++ i) cin >> a[i] ;
stable_sort(a + 1 , a + n + 1) ;
dp[0][0][0][0] = 1 ;
for (int i = 0 ; i < n ; ++ i) {
for (int j = 0 ; j <= i ; ++ j) {
for (int k = 0 ; k <= m ; ++ k) {
for (int d = 0 ; d <= 2 ; ++ d) {
ll k2 = 1ll * (2 * j - d) * (a[i + 1] - a[i]) + 1ll * k ;
if (k2 > m || k2 < 0) continue ;
if (!dp[i][j][k][d]) continue ;
if (j >= 2) dp[i + 1][j - 1][k2][d] = (1ll * dp[i + 1][j - 1][k2][d] + 1ll * dp[i][j][k][d] * (j - 1)) % mod ; // 合并两个区间
if (j >= 1) dp[i + 1][j][k2][d] = (1ll * dp[i + 1][j][k2][d] + 1ll * dp[i][j][k][d] * (2 * j - d)) % mod ; // 并在一个区间左右且不为端点
dp[i + 1][j + 1][k2][d] = (1ll * dp[i + 1][j + 1][k2][d] + 1ll * dp[i][j][k][d] * (j + 1 - d)) % mod ; // 重开一个且不为端点
if (d < 2 && j >= 1) dp[i + 1][j][k2][d + 1] = (1ll * dp[i + 1][j][k2][d + 1] + 1ll * dp[i][j][k][d] * (2 - d)) % mod ; // 并在一个区间左右且为端点
if (d < 2) dp[i + 1][j + 1][k2][d + 1] = (1ll * dp[i + 1][j + 1][k2][d + 1] + 1ll * dp[i][j][k][d] * (2 - d)) % mod ; // 重开一个且为端点
}
}
}
}
ll ans = 0 ;
for (int i = 0 ; i <= m ; ++ i) {
ans = (ans + 1ll * dp[n][1][i][2]) % mod ;
}
cout << ans ;
}
预设型 DP的更多相关文章
- DP搬运工1 [来自yyy--mengbier的预设型dp]
DP搬运工1 题目描述 给你 \(n,K\) ,求有多少个 \(1\) 到 \(n\) 的排列,满足相邻两个数的 \(max\) 的和不超过 \(K\). 输入格式 一行两个整数 \(n,K\). 输 ...
- 区间型DP
区间型DP是一类经典的动态规划问题,主要特征是可以先将大区间拆分成小区间求解最后由小区间的解得到大区间的解. 有三道例题 一.石子合并 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆. ...
- POJ3659 Cell Phone Network(树上最小支配集:树型DP)
题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...
- POJ_1088 滑雪(记忆型DP+DFS)
Description Michael喜欢滑雪,这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者等待升降机来载你.Michael想知道 ...
- UVA12186--树型DP
树型DP第一题...就是从boss到底层员工是一个树型结构,底层员工想加薪,如果每个boss都有超过T%的员工要求加薪,他就会往更高的bOSs传达,问如果让根节点的大boss接到加薪要求,最少要有多少 ...
- POJ 3342 - Party at Hali-Bula 树型DP+最优解唯一性判断
好久没写树型dp了...以前都是先找到叶子节点.用队列维护来做的...这次学着vector动态数组+DFS回朔的方法..感觉思路更加的清晰... 关于题目的第一问...能邀请到的最多人数..so ea ...
- 【XSY1905】【XSY2761】新访问计划 二分 树型DP
题目描述 给你一棵树,你要从\(1\)号点出发,经过这棵树的每条边至少一次,最后回到\(1\)号点,经过一条边要花费\(w_i\)的时间. 你还可以乘车,从一个点取另一个点,需要花费\(c\)的时间. ...
- 洛谷P3354 Riv河流 [IOI2005] 树型dp
正解:树型dp 解题报告: 传送门! 简要题意:有棵树,每个节点有个权值w,要求选k个节点,最大化∑dis*w,其中如果某个节点到根的路径上选了别的节点,dis指的是到达那个节点的距离 首先这个一看就 ...
- 【POJ 3140】 Contestants Division(树型dp)
id=3140">[POJ 3140] Contestants Division(树型dp) Time Limit: 2000MS Memory Limit: 65536K Tot ...
- 「bzoj1925」「Sdoi2010」地精部落 (计数型dp)
「bzoj1925」「Sdoi2010」地精部落---------------------------------------------------------------------------- ...
随机推荐
- lumen、laravel 环境问题汇总
框架报500 1.chmod 777 -R storage 将日志目录权限设置下. 2.修改fastcgi,将代码目录包含进去. fastcgi_param PHP_ADMIN_VALUE " ...
- 可重入锁思想,设计MQ迁移方案
如果你的MQ消息要从Kafka切换到RocketMQ且不停机,怎么做?在让这个MQ消息调用第三方发奖接口,但无幂等字段又怎么处理?今天小傅哥就给大家分享一个关于MQ消息在这样的场景中的处理手段. 这是 ...
- Unity中自定义应用程序打开Assets目录下指定类型的文件
在Unity使用VS2017打开unityShader文件时总提示错误: 我也一直没找啥原因,shader文件直接使用VSCode打开,当然其他类型的文件也可这样处理用相应的exe打开,如:pdf,t ...
- MySQL 并发控制(锁得使用)
导读 并发问题:同一时刻进行读写,并发问题回引发数据不一致问题. 解决并发问题:MySQL采用了锁定机制去解决并发问题 锁的分类 MySQL使用两种锁机制去解决问题:共享锁和排他锁,也叫读锁或者写锁. ...
- mac idea 配置Tomcat
官网下载Tomcat 下载地址:点我直达 配置Idea 设置Application Servers 操作步骤:Intellij IDEA->Preferences->Application ...
- Linux-shell编程入门基础
目录 前言 Shell编程 bash特性 shell作用域 变量 环境变量 $特殊变量 $特殊状态变量 $特殊符号(很重要) 其他内置shell命令 shell语法的子串截取 统计 指令执行时间 练习 ...
- MySQL索引是怎么支撑千万级表的快速查找?
前言 在 MySQL 官方提到,改善操作性能的最佳方法 SELECT 在查询中测试的一个或多个列上创建索引.索引条目的作用类似于指向表行的指针,从而使查询可以快速确定哪些行与WHERE子句中的条件匹配 ...
- .NET Core 3.x 基于AspectCore实现AOP,实现事务、缓存拦截器
最近想给我的框架加一种功能,就是比如给一个方法加一个事务的特性Attribute,那这个方法就会启用事务处理.给一个方法加一个缓存特性,那这个方法就会进行缓存.这个也是网上说的面向切面编程AOP. A ...
- TIER 1: Crocodile
TIER 1: Crocodile nmap 在前几次练习中,我们已经熟悉 nmap 扫描,我们在本次靶机中使用继续使用 nmap 进行扫描. 扩充我们的知识库:-sC 选项启用了 Nmap 的默认脚 ...
- C# 开发技巧 轻松监控方法执行耗时
前言 MethodTimer.Fody 是一个功能强大的库,可以用于测量 .NET 应用程序中的方法的执行时间.允许你在不修改代码的情况下,自动地测量和记录方法的执行时间. 这个工具是基于.NET的 ...