1.普通状态压缩 DP

oi-wiki

I.P1896 [SCOI2005] 互不侵犯

\(f_{i,j,st}\) 表示前 \(i\) 行中放置了 \(j\) 个国王,当前行状态为 \(st\) 的方案数。可以预处理出合法的状态与其 popcount,转移时枚举当前行状态和上一行状态,合法就转移。

const int N = 20,inf = 1e9,mod = 998244353;
const ll inff = 1e18;
int n,k,f[N][110][1000];
vector<int> v; int pcnt[1000]; il void solve() {
//------------code------------
read(n,k);
rep(st,0,(1 << n) - 1) if (!((st << 1) & st) && !((st >> 1) & st))
v.pb(st),pcnt[st] = __builtin_popcount(st);
f[0][0][0] = 1;
rep(i,1,n) for (auto st : v) for (auto stt : v)
if (!(stt & st) && !((stt << 1) & st) && !((stt >> 1) & st)) {
rep1(j,k,pcnt[st]) f[i][j][st] += f[i - 1][j - pcnt[st]][stt];
}
int ans = 0;
for (auto st : v) ans += f[n][k][st];
write(ans,'\n');
// cerr << "Time : " << (db)(end - start) / CLOCKS_PER_SEC << " s" << endl;
return ;
}

II.P2704 [NOI2001] 炮兵阵地

考虑将一行某个位置能否部署状压成一个二进制数,然后判断状态合法时可以直接把它们按位与起来。\(f_{i,st,st'}\) 表示前 \(i\) 行中,当前行状态为 \(st\),上一行状态为 \(st'\),最多能摆放的炮兵部队的数量。压掉一维就能过。

const int N = 110,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N];
int f[3][1034][1034];
vector<PII> v; il void solve() {
//------------code------------
read(n,m);
rep(i,1,n) {
string s; cin >> s;
rep(j,0,m - 1) a[i] += (s[j] == 'H') * (1 << (m - 1 - j));
}
rep(st,0,(1 << m) - 1) if (!(st & (st >> 1)) && !(st & (st >> 2))) v.pb(st,__builtin_popcount(st));
memset(f,-0x3f,sizeof f);
for (auto x : v) f[1][x.fst][0] = x.snd;
rep(i,2,n)
for (auto st : v) if (!(st.fst & a[i]))
for (auto stt : v) if (!(st.fst & stt.fst) && !(stt.fst & a[i - 1]))
for (auto sttt : v) if (!(st.fst & sttt.fst) && !(stt.fst & sttt.fst) && !(sttt.fst & a[i - 2]))
chmax(f[i % 3][st.fst][stt.fst],f[(i - 1) % 3][stt.fst][sttt.fst] + st.snd);
int ret = 0;
for (auto st : v) if (!(st.fst & a[n]))
for (auto stt : v) if (!(st.fst & stt.fst) && !(stt.fst & a[n - 1]))
chmax(ret,f[n % 3][st.fst][stt.fst]);
write(ret,'\n');
return ;
}

III.P1879 [USACO06NOV] Corn Fields G

板子。\(f_{i,st}\) 表示前 \(i\) 行中当前行状态为 \(st\) 的种植方案数。

const int N = 22,inf = 1e9,mod = 1e8;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N]; ll f[N][4100];
vector<int> v; il void solve() {
//------------code------------
read(n,m);
rep(i,1,n)
rep(j,1,m) {
int x; read(x);
a[i] += (1 << (m - j)) * (!x);
}
rep(st,0,(1 << m) - 1) if (!(st & (st << 1))) v.pb(st);
f[0][0] = 1;
rep(i,1,n)
for (auto st : v) if (!(st & a[i]))
for (auto stt : v) if (!(st & stt) && !(stt & a[i - 1]))
f[i][st] = (f[i][st] + f[i - 1][stt]) % mod;
ll ans = 0;
for (auto st : v) ans = (ans + f[n][st]) % mod;
write(ans,'\n');
return ;
}

IV.P3052 [USACO12MAR] Cows in a Skyscraper G

\(f_{st}\) 表示当前已将哪些物品进行分组,最小的分组数量。维护一个当前 \(f_{st}\) 的最大剩余体积,每次能放下就放,放不下就增加组数,同时更新最大剩余体积。

const int N = 3e5 + 10,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,w[20]; PII f[N]; il void solve() {
//------------code------------
read(n,m);
rep(i,1,n) read(w[i]);
rep(st,1,(1 << n) - 1) f[st] = {-inf,inf};
f[0] = {m,1};
rep(st,1,(1 << n) - 1)
rep(i,0,n - 1) if (st >> i & 1) {
if (f[st].snd >= f[st ^ (1 << i)].snd && f[st ^ (1 << i)].fst >= w[i + 1]) {
chmax(f[st].fst,f[st ^ (1 << i)].fst - w[i + 1]);
f[st].snd = f[st ^ (1 << i)].snd;
} else if (f[st].snd >= f[st ^ (1 << i)].snd + 1 && f[st ^ (1 << i)].fst < w[i + 1]) {
chmax(f[st].fst,m - w[i + 1]);
f[st].snd = f[st ^ (1 << i)].snd + 1;
}
// cerr << st << " " << i << " " << f[st].snd << '\n';
}
write(f[(1 << n) - 1].snd,'\n');
return ;
}

V.P2396 yyy loves Maths VII

显然有 \(\mathcal{O(2^n n)}\) 的做法,但是 1 s 可能跑不过,考虑优化 \(n\) 的那一维,每次取出状态的 lowbit 来进行转移,并减掉它,这样可以减少大量无用的判断,能过此题。最慢的点跑了有 600 ms

const int N = 2e7 + 10,inf = 1e9,mod = 1e9 + 7;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,a[N],b[3],f[N],g[N]; il int lowbit(int x) { return x & -x; } il void solve() {
//------------code------------
read(n); rep(i,1,n) read(a[(1 << i - 1)]);
read(m); rep(i,1,m) read(b[i]);
f[0] = 1;
rep(st,1,(1 << n) - 1) {
g[st] = g[st ^ lowbit(st)] + a[lowbit(st)];
bool fl = 1;
rep(i,1,m) if (g[st] == b[i]) { fl = 0; break; }
if (!fl) continue;
int x = st;
for (; x; x -= x & -x) f[st] = (f[st] + f[st ^ lowbit(x)]) % mod;
}
write(f[(1 << n) - 1],'\n');
return ;
}

VI.P2831 [NOIP2016 提高组] 愤怒的小鸟

可以发现两个点可以唯一确定一条抛物线,预处理 \(sta_{i,j}\) 表示第 \(i\) 个点和第 \(j\) 个点组成的抛物线经过的点,对其做状压处理。现在就有一个 \(\mathcal{O(T2^n n^2)}\) 的做法,对于当前状态枚举接下来打哪条抛物线。这样并不能通过所有测试点,考虑优化。发现最终需要的答案是 \(f_{2^n - 1}\),其余有 \(f\) 对最终答案并没有贡献,那么它是无用的,显然我们最终状态 \(2^n - 1\) 在二进制下是有 \(n\) 个 1 的,那么每次对于当前状态要推到最终状态,二进制下第一个为 0 的位置到最后一定会被转移掉,变为 1,那么我们就可以找到这个位置,再枚举它和其它的点的抛物线,用此抛物线的 \(sta\) 来转移就足矣。最后时间复杂度是 \(\mathcal{O(T2^n n)}\) 的。

const int N = 270010,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const db eps = 1e-8;
const ll inff = 1e18;
int n,m; pair<db,db> a[N];
int cnt[20][20],f[N]; il void solve() {
//------------code------------
read(n,m);
rep(i,1,n) cin >> a[i].fst >> a[i].snd;
rep(i,1,n) rep(j,i + 1,n) {
db x = a[i].fst,y = a[i].snd;
db xx = a[j].fst,yy = a[j].snd;
if (fabs(x - xx) < eps) { cnt[i][j] = cnt[j][i] = 0; continue; }
db A = (y / x - yy / xx) / (x - xx),B = y / x - x * A;
// cerr << i << " " << j << " " << A << " " << B << '\n';
if (A >= 0) { cnt[i][j] = cnt[j][i] = 0; continue; }
cnt[i][j] = 0;
rep(k,1,n) if (fabs(A * a[k].fst * a[k].fst + B * a[k].fst - a[k].snd) < eps)
cnt[i][j] += (1 << k - 1);
cnt[j][i] = cnt[i][j];
}
rep(st,0,(1 << n) - 1) f[st] = inf;
f[0] = 0;
rep(st,0,(1 << n) - 2) {
int p = -1;
rep(i,0,n - 1) if (!(st >> i & 1)) { p = i; break; }
chmin(f[st | (1 << p)],f[st] + 1);
rep(i,1,n) if (i != p && ~cnt[p + 1][i]) chmin(f[st | cnt[p + 1][i]],f[st] + 1);
}
write(f[(1 << n) - 1],'\n');
return ;
}

VII.P2473 [SCOI2008] 奖励关

显然有 \(f_{i,st}\) 表示前 \(i\) 次中,吃过的宝物的集合为 \(st\) 的最大期望分值。然后你会发现对于 \(f_i\),有一些状态是明显不合法的,此题起点唯一,但终点不唯一且有一些状态不可达的情况,所以需要倒推。

const int N = 20,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int k,n,s[N],p[N];
db f[110][32770]; il void solve() {
//------------code------------
read(k,n);
rep(i,1,n) {
read(p[i]); s[i] = 0;
int x; read(x);
while (x) {
s[i] |= (1 << x - 1);
read(x);
}
}
f[k + 1][(1 << n) - 1] = 0;
rep1(i,k,1)
rep(st,0,(1 << n) - 1) {
// cerr << i << " " << st << '\n';
rep(j,1,n)
if ((st & s[j]) == s[j]) f[i][st] += max((f[i + 1][st | (1 << j - 1)] + p[j] * 1.0),f[i + 1][st]) / (db)n;
else f[i][st] += f[i + 1][st] / (db)n;
}
db ans = f[1][0];
printf("%.6lf\n",ans);
return ;
}

2.插头 DP

插头 DP 用于解决需要维护状态连通性的状压 DP 问题。

oi-wiki

I.「HDU 1400」Mondriaan’s Dream

\(f_{i,j,s}\) 表示当前转移到了 \((i,j)\),轮廓线上的状态为 \(s\) 的合法覆盖方案数。注意状态是按照 \(j\) 的大小从小到大依次存储在二进制位下的。

可以进行分类讨论:

  1. 当状态 \(s\) 的第 \(j - 1\) 位上为 1 而第 \(j\) 位上为 0,即左边有插头过来而上面没有,那么就是横放,下一个状态的第 \(j - 1\) 位应当为 0
  2. 当状态 \(s\) 的第 \(j\) 位上为 1 而第 \(j - 1\) 位上为 0,即上面有插头过来而左边没有,那么就是竖放,下一个状态的第 \(j\) 位应当为 0
  3. 当第 \(j\) 和 \(j - 1\) 位上均为 0 时,即可竖放也可横放,结合以上两种转移即可;
  4. 均为 1 时不合法。
const int N = 15,inf = 1e9,mod = 998244353;
const ull base = 131,base_ = 233;
const ll inff = 1e18;
int n,m,f[N][N][1 << N]; il void solve() {
//------------code------------
while (1 + 1 == 2) {
read(n,m);
if (!n && !m) return ;
rep(i,0,n) rep(j,0,m) rep(s,0,(1 << m + 1) - 1) f[i][j][s] = 0;
f[1][0][0] = 1;
rep(i,1,n) {
rep(j,1,m) {
rep(s,0,(1 << m + 1) - 1) {
if (!(s >> (j - 1) & 1)) f[i][j][s ^ (1 << j)] += f[i][j - 1][s];
if (!(s >> j & 1)) f[i][j][s ^ (1 << j - 1)] += f[i][j - 1][s];
}
}
rep(s,0,(1 << m + 1) - 1) if (!(s >> m)) f[i + 1][0][s << 1] = f[i][m][s];
}
write(f[n + 1][0][0],'\n');
}
return ;
}

「UVA 11270」Tiling Dominoes

双倍经验。同上。

等待更新。。

状压 DP 做题记录的更多相关文章

  1. 状压dp做题笔记

    CodeChef Factorial to Square (分块决策) Description 给定一个n,要求在[1,n]中删除一些数,并使剩下的数的乘积是一个完全平方数,同时要求乘积最大,求删除方 ...

  2. 【bzoj3195】【 [Jxoi2012]奇怪的道路】另类压缩的状压dp好题

    (上不了p站我要死了) 啊啊,其实想清楚了还是挺简单的. Description 小宇从历史书上了解到一个古老的文明.这个文明在各个方面高度发达,交通方面也不例外.考古学家已经知道,这个文明在全盛时期 ...

  3. 7月15日考试 题解(链表+状压DP+思维题)

    前言:蒟蒻太弱了,全打的暴力QAQ. --------------------- T1 小Z的求和 题目大意:求$\sum\limits_{i=1}^n \sum\limits_{j=i}^n kth ...

  4. 【bzoj1087】【互不侵犯King】状压dp裸题(浅尝ACM-D)

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=54329606 向大(hei)佬(e)势力学(di ...

  5. POJ 3254 - Corn Fields - [状压DP水题]

    题目链接:http://poj.org/problem?id=3254 Time Limit: 2000MS Memory Limit: 65536K Description Farmer John ...

  6. hdu 1185 状压dp 好题 (当前状态与上两行有关系)

    /* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);( ...

  7. poj 3254 状压dp入门题

    1.poj 3254  Corn Fields    状态压缩dp入门题 2.总结:二进制实在巧妙,以前从来没想过可以这样用. 题意:n行m列,1表示肥沃,0表示贫瘠,把牛放在肥沃处,要求所有牛不能相 ...

  8. DP 做题记录 II.

    里面会有一些数据结构优化 DP 的题目(如 XI.),以及普通 DP. *I. P3643 [APIO2016]划艇 题意简述:给出序列 \(a_i,b_i\),求出有多少序列 \(c_i\) 满足 ...

  9. HihoCoder - 1048 状压DP 经典题

    hihocoder题解说的十分清晰了,这份代码就是从讲解里学习的 方案数就是不断枚举合法状态下横放竖放或两者均可 合法判断的依据是记录当前行和下一行的状态 防止重复枚举的方法是先按行后按列 递归基瞎写 ...

  10. 二维状压DP经典题

    炮兵阵地 题目链接 题目大意:在n*m的地图上放置炮兵,每个炮兵的攻击范围是上下左右两格内,有两种不同的地形,山地(用"H" 表示),平原(用"P"表示),只有 ...

随机推荐

  1. Ubuntu 22.04 LTS 在线/离线安装 Docker

    Docker 安装方式 时间:2024-10 准备环境 root@ubuntu2204:~# hostnamectl Static hostname: ubuntu2204 Icon name: co ...

  2. 全面解释人工智能LLM模型的真实工作原理(完结)

    前一篇:<全面解释人工智能LLM模型的真实工作原理(三)> 序言: 本节作为整篇的收官之作,自然少不了与当今最先进的AI模型相呼应.这里我们将简单介绍全球首家推动人工智能生成人类语言的公司 ...

  3. Postman 免登录测试后端接口

    今天跟测试同学学习了下用Postman免登录测试后端接口,测试同学除了会对我们系统前端测试外,一些后端接口涉及危险操作也会使用Postman 对接口进行测试,这个时候就需要解决一个接口免登录的问题,他 ...

  4. jenkins集成cucumber-resport报告

    需要安装的jenkins插件-Cucumber Reports jenkins版本:2.273 jenkins插件下载地址:点击下载 下载插件后通过jenkins插件管理上传已下载好的插件即可 等待j ...

  5. 使用tensorboard可视化模型

    Tensorboard是TF自带的可视化工具.它可以让我们从各个角度观察与修改模型,比如观察模型在训练时的loss动态变化曲线而无需在迭代完毕后再画图.绘制神经网络的结构图.调节超参数等.下面以最简单 ...

  6. bootstrapTable初始化常用参数

    bootstrapTable初始化常用参数,前端分页排序,后端获取表格数据 $('#table').bootstrapTable({ toolbar: '#mybar', //工具按钮用哪个容器 st ...

  7. MySQL底层概述—9.ACID与事务

    大纲 1.ACID之原子性 2.ACID之持久性 3.ACID之隔离性 4.ACID之一致性 5.ACID的关系 6.事务控制演进之排队 7.事务控制演进之排它锁 8.事务控制演进之读写锁 9.事务控 ...

  8. Vue.js 组件数据交互

    1.前言 本节讲述组件之间如何进行数据交互 2.props属性与非 prop 的属性 父组件通过属性绑定的形式传值给子组件,这种传值分2种 类别 含义 说明 props 子组件本身已经通过props定 ...

  9. 实现不可逆加密文件:探索 GodoOS 的安全机制

    在当今数字化时代,数据安全成为了企业和个人关注的重点.为了保护敏感信息不被未授权访问,各种加密技术应运而生.本文将探讨 GodoOS 项目中实现的一种不可逆加密文件的方法,重点介绍其背后的原理和技术细 ...

  10. 使用Docker快速部署一个Net项目

    前言 Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 优点 Web 应用的自动化打包和发布. 自动化测试和 ...