暑假集训 || 状压DP
emm
位操作实现技巧:
获得第i位的数据: if(!(data & (1<< i))) 则data的第 i 位为0,else 为 1
设置第i位为1,data=(data | (1<< i));
设置第i位为0,data=(data & (~(1<< i)))
将第i位取反,data=(data ^ (1<< i)
取出一个数的最后一个1 (lowbit):(data & (-data))
(二进制数从右往左最右为第0位)
Codeforces gym 101343 J
题意:给出一片田野,其中有0有1,1的地方可以选,挨着的两个格不能选,问有多少种选法
思路:把田野上可以选的状态用二进制表示,进行dp,因为每一行的情况只与它上一行有关
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int SZ = ;
const int INF = ;
const int mod = ;
int tmp;
int f[][SZ], st[SZ], a[];
int m, n;
bool check(int x, int y)//判断田野情况为x时,y方案能不能放
{
bool flag = true;
for(int i = ; i < n; i++)
if((x&( << i)) == && (y&( << i)) > ) flag = false;//田野上这个点是0,而方案中这个点要放,不可以呀
return flag;
}
void init()//初始化出所有可能存在的状态
{
int tot = ;
for(int i = ; i < (<<n); i++)
if(!(i & (i<<))) st[++tot] = i;
}
int main()
{
scanf("%d %d", &m, &n);
for(int i = ; i <= m; i++) a[i] = , f[i] = ;
for(int i = ; i <= m; i++)
for(int j = ; j <= n; j++)
{
scanf("%d", &tmp);
if(tmp) a[i] = a[i] | (<<(n-j));//将这一位设为1
}
for(int i = ; i <= tot; i++)
{
if(check(a[], st[i])) f[][i] = ;
}
for(int i = ; i <= m; i++)
for(int j = ; j <= tot; j++)//枚举第i行的状态
if(check(a[i], st[j]))//第i行的j状态合法
for(int k = ; k <= tot; k++)//枚举第i-1行状态
if(check(a[i-], st[k]) && !(st[k] & st[j]))
f[i][j] = (f[i][j] + f[i-][k]) % mod;
int ans = ;
for(int i = ; i <= tot; i++)
ans = (ans + f[m][i]) % mod;
printf("%d\n", ans);
return ;
}
POJ 3254
题意:构造一个序列,包括给出的n个子序列,问这个序列的最短长度
思路:第一反应贪心 然鹅是枚举去做状压dp
f[i][j] 表示状态 i 中最后一个序列是 j 的长度,下次更新的时候在它后面接k
把k接在它后面 f[i|(1<<(k-1))][k] = min{f[i][j] + num[k] - arr[j][k]};
细节:预处理每两个数组可以互相覆盖的大小之前要处理一下完全包含的情况
然后。。1<<(i-1) QAQ窝数组下标是从1开始开的哇。。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int SZ = ;
const int INF = ;
const int mod = ;
int num[], a[][], arr[][];
int f[SZ][], vis[];
int main()
{
int n;
scanf("%d", &n);
for(int i = ; i <= n; i++)
{
scanf("%d", &num[i]);
for(int j = ; j <= num[i]; j++)
scanf("%d", &a[i][j]);
}
for(int i = ; i <= n; i++)//除去被a[i]包含的串//1 2 3 4 5
{
if(vis[i]) continue;
for(int j = ; j <= n; j++)//看看a[j]有没有被a[i]包含//2 3 4
{
if(i == j || vis[j] || num[i] < num[j]) continue;
for(int k = ; k <= num[i]; k++)
{
if(k + num[j] - > num[i]) break;
bool same = true;
for(int tj = ; tj <= num[j]; tj++)
if(a[i][k+tj-] != a[j][tj]) same = false;
if(same) {vis[j] = ; break;}
}
}
}
int idx = ;
for(int i = ; i <= n; i++)
if(!vis[i])
{
num[++idx] = num[i];
for(int j = ; j <= num[i]; j++)
a[idx][j] = a[i][j];
}
n = idx;
for(int i = ; i <= n; i++)//把j接在i后面
for(int j = ; j <= n; j++)
{
if(i == j) continue;
for(int len = ; len <= num[i]; len++)
{
bool flag = true;
for(int k = ; k <= len; k++)
if(a[i][num[i]-len+k] != a[j][k]) flag = false;
if(flag) arr[i][j] = len;
}
}
memset(f, , sizeof(f));
for(int i = ; i <= n; i++)
f[<<(i-)][i] = num[i];
for(int i = ; i < (<<n); i++)
for(int j = ; j <= n; j++)
for(int k = ; k <= n; k++)//在j后放k
if(i&(<<(j-)) || !i&(<<(k-)))
f[i|(<<(k-))][k] = min(f[i|(<<(k-))][k], f[i][j] + num[k] - arr[j][k]);
int ans = INF;
for(int i = ; i <= n; i++)
ans = min(ans, f[(<<n)-][i]);
printf("%d\n", ans);
return ;
}
BZOJ 1087
题意:在N×N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案。国王能攻击到它一圈的八个地方(1 <=N <=9, 0 <= K <= N * N)
思路:看到这个数据范围就想到状压,每一行的情况都能用一个9位二进制数表示
f[i][j] 表示第 i 行放 j 情况的方法数,从f[i-1][k]转移而来,转移时判断 j 和 k 是否冲突
因为总共的数量有限制,所以再加一维表示到当前放了多少个
c数组表示这种情况下有多少个1
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int SZ = ;
const int INF = ;
const int mod = ;
LL f[][SZ][], st[SZ], c[SZ];
int m, n;
//f[i][j][k] 第i行,状态为st[j],已经放了k个
bool check(int x, int y)
{
bool flag = true;
if(y&x || y&(x<<) || y &(x>>)) flag = false;
return flag;
} int main()
{
scanf("%d %d", &n, &m);
int tot = ;
for(int i = ; i < (<<n); i++)
if(!(i & (i<<)))
{
st[++tot] = i;
for(int j = ; j < n; j++)
if(i&(<<j)) c[tot]++;
}
for(int i = ; i <= tot; i++)
f[][i][c[i]] = ;
for(int i = ; i <= n; i++)
for(int j = ; j <= tot; j++)//枚举第i行的状态
for(int k = ; k <= tot; k++)//枚举第i-1行状态
{
if(check(st[j], st[k]))
{
for(int t = c[j]; t <= m; t++)
f[i][j][t] += f[i-][k][t-c[j]];
}
}
LL ans = ;
for(int i = ; i <= tot; i++)
ans += f[n][i][m];
printf("%lld\n", ans);
return ;
}
暑假集训 || 状压DP的更多相关文章
- 暑假集训Day2 互不侵犯(状压dp)
这又是个状压dp (大型自闭现场) 题目大意: 在N*N的棋盘里面放K个国王,使他们互不攻击,共有多少种摆放方案.国王能攻击到它上下左右,以及左上左下右上右下八个方向上附近的各一个格子,共8个格子. ...
- 暑假集训Day 4 P4163 [SCOI2007]排列 (状压dp)
状压dp (看到s的长度不超过10就很容易想到是状压dp了 但是这个题的状态转移方程比较特殊) 题目大意 给一个数字串 s 和正整数 d, 统计 s 有多少种不同的排列能被 d 整除(可以有前导 0) ...
- 暑假集训Day2 状压dp 特殊方格棋盘
首先声明 : 这是个很easy的题 可这和我会做有什么关系 题目大意: 在n*n的方格棋盘上放置n个车,某些格子不能放,求使它们不能互相攻击的方案总数. 注意:同一行或同一列只能有一个车,否则会相互攻 ...
- 【uoj#37/bzoj3812】[清华集训2014]主旋律 状压dp+容斥原理
题目描述 求一张有向图的强连通生成子图的数目对 $10^9+7$ 取模的结果. 题解 状压dp+容斥原理 设 $f[i]$ 表示点集 $i$ 强连通生成子图的数目,容易想到使用总方案数 $2^{sum ...
- 【62测试】【状压dp】【dfs序】【线段树】
第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- nefu1109 游戏争霸赛(状压dp)
题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...
- poj3311 TSP经典状压dp(Traveling Saleman Problem)
题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...
- [NOIP2016]愤怒的小鸟 D2 T3 状压DP
[NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...
随机推荐
- python-day9-进程、线程、协程篇
python threading模块 线程有两种调用方式: 直接调用 import threading import time def sayhi(num): #定义每个线程要运行的函数 print( ...
- bzoj2839
容斥原理+组合数学 看见这种恰有k个的题一般都是容斥原理,因为恰有的限制比较强,一般需要复杂度较高的方法枚举,而容斥就是转化为至少有k个,然后通过容斥原理解决 我们先选出k个元素作为交集,有C(n,k ...
- InstallShield 12 豪华版+破解版 下载
InstallShield 12 豪华版+破解版 下载 2009-07-09 19:18:30| 分类: 默认分类|字号 订阅 InstallShield 12 豪华版+破解版 下载 下载方 ...
- linux下ping不通的解决方法
转自:https://blog.csdn.net/weixin_33400820/article/details/80227702 今天在做练习的时候,发现如何都无法ping通外网,在经过各种网络求助 ...
- Hibernate 4.3 配置文件实现
1.建立web项目 2.复制相关的jar文件到 项目的lib目录下antlr-2.7.7.jardom4j-1.6.1.jarhibernate-commons-annotations-4.0.5.F ...
- 51单片机 HC05蓝牙模块
一.注意事项 1.烧写程序时,要把蓝牙tx,rx信号线拔掉,对烧写程序有影响. 2.执行HC05集命令时,均以\r\n结尾.串口中断若选择“发送新行”时,不用添加\r\n.原理相同. 二.准备软硬件 ...
- bzoj 3262 陌上花开 【CDQ分治】
三维偏序 首先把所有花按 x一序,y二序,z三序 排序,然后去重,con记录同样的花的个数,然后进行cdq 现在假设有[l.r]区间,其中[l,mid] [mid+1,r],已经递归处理完毕.我们把区 ...
- (二分图最大匹配)51NOD 2006 飞行员配对
第二次世界大战时期,英国皇家空军从沦陷国征募了大量外籍飞行员.由皇家空军派出的每一架飞机都需要配备在航行技能和语言上能互相配合的2名飞行员,其中1名是英国飞行员,另1名是外籍飞行员.在众多的飞行员中, ...
- jqgrid 分级标题
参考地址:http://www.trirand.com/jqgridwiki/doku.php?id=wiki:groupingheadar Grouping of the header should ...
- hdu 4442 Physical Examination (2012年金华赛区现场赛A题)
昨天模拟赛的时候坑了好久,刚开始感觉是dp,仔细一看数据范围太大. 题目大意:一个人要参加考试,一共有n个科目,每个科目都有一个相应的队列,完成这门科目的总时间为a+b*(前面已完成科目所花的总时间) ...