状压dp专题复习

(有些题过于水,我直接跳了)

技巧总结 :

1.矩阵状压上一行的选择情况 \(n * 2^n\)

D [BZOJ2734][HNOI2012]集合选数

蒻得不行的我觉得这是一道比较难的题,以至于我卡了很久

可以看出,所有会互相直接造成影响的数之间构成一张\(DAG\),边就是\(i->i*2,i->i*3\)

取出每一个连通块之后,就是一个独立集个数的问题

\(DAG\)还可以求独立集?

我们其实可以惊人得发现,这张\(DAG\)过于整齐,就是一个网格图,就是一张网格图上相邻的点不能取的问题

这个,状压矩阵即可


const int N=1e5+10,P=1e9+1; int n;
ll dp[20][1<<11];
int A[20]; ll Solve(int i){
int t=0;
A[0]=0;
dp[0][0]=1;
for(;i<=n;i*=2) {//网格图的列数
t++;
A[t]=0;
int c=0;
for(int j=i;j<=n;j*=3) A[t]|=1<<(c++); //取出网格图这一行的大小
rep(j,0,A[t]) dp[t][j]=0;
rep(S1,0,A[t-1]) {
int fl=1;
rep(j,0,c+1) if((S1&(1<<j)) && (S1&(1<<(j+1)))) fl=0;
if(!fl) continue;
int R=A[t]^(S1&A[t]);
for(reg int S2=R;;S2=(S2-1)&R) {
int fl=1;
rep(j,0,c-1) if((S2&(1<<j)) && (S2&(1<<(j+1)))) fl=0;
if(!fl) {
if(!S2) break;
continue;
}
(dp[t][S2]+=dp[t-1][S1])%=P;
if(!S2) break;
}
}
}
ll res=0;
rep(i,0,A[t]) res+=dp[t][i];
res%=P;
return res;
} int main(){
n=rd();
ll ans=1;
rep(i,1,n) {
if(i%2==0||i%3==0) continue;
//这是一个联通块
ans=ans*Solve(i)%P;
}
printf("%lld\n",ans);
}

\[\
\]

\[\
\]

G [BZOJ1097] [POI2007]旅游景点atr

预处理前面k个点之间的dis,然后就像是一个TSP一样,但是有限制

int d[30][30];
#include<bits/stdc++.h>
using namespace std; #define reg register
//typedef long long ll;
typedef int ll;
#define rep(i,a,b) for(reg int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(reg int i=a,i##end=b;i>=i##end;--i) char IO; int rd(){
int s=0,f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
} const int N=20010,M=2e5+10; #pragma GCC optimize(3)
#pragma GCC optimize(2)
#define chk(a,b) ((a>b)&&(a=b)) int n,m,k; ll dis[N]; struct Node{
int x;
ll d;
int operator < (const Node __) const{
return x<__.x;
}
};
vector <Node> G[N]; int s[N<<2]; int pos[N]; inline void push(reg int x) {
int p=pos[x];
while(p>1) {
p>>=1;
if(dis[s[p<<1]]<dis[s[p<<1|1]]) s[p]=s[p<<1];
else s[p]=s[p<<1|1];
}
} inline int top(){
reg int x=s[1];
s[pos[x]]=0;
push(x);
return x;
} void Build(int p,int l,int r) {
if(l==r) {
pos[l]=p;
return;
}
reg int mid=(l+r)>>1;
Build(p<<1,l,mid);
Build(p<<1|1,mid+1,r);
}
//用线段树实现堆的功能 void GetDis(int st,int R) {
memset(dis,63,sizeof dis); dis[st]=0;
for(reg int i=1;i<=n;++i) s[pos[i]]=i;
push(st);
int cnt=0;
while(dis[s[1]]<=1e9) {
reg int u=top();
if(u<=R && (++cnt>=R) ) return;
rep(i,0,G[u].size()-1) {
int v=G[u][i].x,w=G[u][i].d;
if(dis[v]<=dis[u]+w) continue;
dis[v]=dis[u]+w;
push(v);
}
}
} int fa[35];
int dp[1<<20][22];
int Log[1<<21]; int tmp[35]; int main(){
n=rd(),m=rd();
k=rd()+1;
rep(i,0,21) Log[1<<i]=i;
rep(i,1,m) {
int u=rd(),v=rd(),w=rd();
G[u].push_back((Node){v,w});
G[v].push_back((Node){u,w});
}
int q=rd();
rep(i,1,q) {
int u=rd(),v=rd();
fa[v]|=1<<(u-2);
}
Build(1,1,n);
rep(i,1,k) {
GetDis(i,k);
rep(j,1,k) d[i][j]=dis[j];
}
GetDis(n,n);
int A=(1<<(k-1))-1;
memset(dp,63,sizeof dp);
dp[0][1]=0;
for(reg int S=0;S<A;++S) {
reg int T=S;
int cnt=0;
rep(j,0,k-2) if(~S&(1<<j)) if((fa[j+2]&S)==fa[j+2]) tmp[++cnt]=j+2;
while(T) {
reg int i=Log[T&-T]+2;
T&=T-1;
if(dp[S][i]>1e9) continue;
rep(k,1,cnt) {
int j=tmp[k];
reg int NS=S|(1<<(j-2));
chk(dp[NS][j],dp[S][i]+d[i][j]);
}
}
do {
reg int i=1;
if(dp[S][i]>1e9) continue;
rep(k,1,cnt) {
int j=tmp[k];
reg int NS=S|(1<<(j-2));
chk(dp[NS][j],dp[S][i]+d[i][j]);
}
} while(0);
}
ll ans=1e9;
rep(i,1,k) ans=min(ans,dp[A][i]+dis[i]);
printf("%d\n",ans);
}

\[\
\]

\[\
\]

H [BZOJ2004] [Hnoi2010]Bus 公交线路

\(n\)都\(10^9\)了,还不矩阵吗?

\(dp[S]\)表示前\(p\)位哪些点放了车,不过状态显然保证\(popcount(S)==k\)

然后由于状态最多其实是\(C_{10}^{5}=252\)所以可以跑矩阵


bool be; int n,p,k; int dp[1<<10];
int cnt[1<<10];
int tmp[1<<10];
int A; int st[300],sc,id[1<<10];
int f[1][300],ans[1][300]; int B; struct Mat{
int a[300][300];
void init(){ memset(a,0,sizeof a); }
void Get1(){ rep(i,1,sc) a[i][i]=1; }
Mat operator * (const Mat x) const {
Mat res;
for(reg int i=1;i<=sc;++i) {
for(reg int j=1;j<=sc;++j) {
ll t=0;
for(reg int o=1;o<=sc;++o) t+=a[i][o]*x.a[o][j];
res.a[i][j]=t%P;
}
}
return res;
}
}res,x; void Solve(){
A=(1<<p)-1;
rep(i,1,A) cnt[i]=cnt[i&(i-1)]+1;
rep(S,0,A) if(cnt[S]==k) ++sc,id[st[sc]=S]=sc;
rep(S,0,A) if(cnt[S]==k) {
if(S&1) {
x.a[id[S]][id[(S>>1)|(1<<(p-1))]]++;
} else {
rep(i,0,p-1) if(S&(1<<i)) {
int NS=((S^(1<<i))>>1)|(1<<(p-1));
x.a[id[S]][id[NS]]++;
}
}
}
int T=0;
for(reg int j=p-1;j>=p-k;j--) T|=1<<j;
f[0][id[T]]=1;
res.Get1();
n-=k;
int t=n;
while(t) {
if(t&1) res=res*x;
x=x*x;
t>>=1;
}
rep(i,0,0) rep(j,1,sc) rep(o,1,sc) (ans[i][o]+=f[i][j]*res.a[j][o])%=P;
T=0;
rep(j,p-k,p-1) T|=1<<j;
printf("%d\n",ans[0][id[T]]);
} bool ed; int main(){
//printf("%.2lf\n",(&ed-&be)/1024.0/1024.0);
n=rd(),k=rd(),p=rd();
Solve();
}

\[\
\]

\[\
\]

L [BZOJ3195] [Jxoi2012]奇怪的道路

题目限定了距离,所以直接dp选了几条边,之前的点每个点的边数是不是奇数

 

const int N=80,P=1000000007;

int n,m,k;

ll dp[31][1<<8][31];
ll C[N][N]; int main(){
n=rd(),m=rd(),k=rd();
k=min(k,n);
C[0][0]=1;
rep(i,1,N-1) {
C[i][0]=1;
rep(j,1,N-1) C[i][j]=(C[i-1][j-1]+C[i-1][j])%P;
}
dp[0][0][0]=1;
rep(i,1,k-1) {
int A=(1<<i)-1;
rep(S,0,A) {
int t=0;
rep(j,0,i-1) if(S&(1<<j)) t++;
rep(R,0,A) {
int NS=(S^R)|((t&1)<<i);
rep(j,0,m) {
for(reg int d=j+t;d<=m;d+=2) {
(dp[i][NS][d]+=C[(d-j-t)/2+i-1][i-1]*dp[i-1][R][j]%P)%=P;
}
}
}
}
}
int A=(1<<k)-1;
rep(i,k,n-1) {
rep(S,0,A) {
int t=0;
rep(j,0,k-1) if(S&(1<<j)) t++;
rep(R,0,A) if((R&1)==(S&1)) {
int NS=((S^R)>>1)|((t&1)<<(k-1));
rep(j,0,m) {
for(reg int d=j+t;d<=m;d+=2) {
(dp[i][NS][d]+=C[(d-j-t)/2+k-1][k-1]*dp[i-1][R][j]%P)%=P;
}
}
}
}
}
ll ans=dp[n-1][0][m];
printf("%lld\n",ans);
}

状压dp专题复习的更多相关文章

  1. ZOJ 3777 - Problem Arrangement - [状压DP][第11届浙江省赛B题]

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3777 Time Limit: 2 Seconds      Me ...

  2. HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]

    题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...

  3. 状压DP复习

    深感自己姿势水平之蒻……一直都不是很会状压DP,NOIP又特别喜欢考,就来复习一发…… 题目来源 Orz sqzmz T1 [BZOJ4197][NOI2015]寿司晚宴 (做过)质因数分解最大的质因 ...

  4. 状压DP复习笔记

    前言 复习笔记第4篇.CSP RP++. 引用部分为总结性内容. 0--P1433 吃奶酪 题目链接 luogu 题意 房间里放着 \(n\) 块奶酪,要把它们都吃掉,问至少要跑多少距离?一开始在 \ ...

  5. kuangbin专题十二 HDU1074 Doing Homework (状压dp)

    Doing Homework Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)To ...

  6. 动态规划专题(一)——状压DP

    前言 最近,决定好好恶补一下我最不擅长的\(DP\). 动态规划的种类还是很多的,我就从 状压\(DP\) 开始讲起吧. 简介 状压\(DP\)应该是一个比较玄学的东西. 由于它的时间复杂度是指数级的 ...

  7. 算法复习——状压dp

    状压dp的核心在于,当我们不能通过表现单一的对象的状态来达到dp的最优子结构和无后效性原则时,我们可能保存多个元素的有关信息··这时候利用2进制的01来表示每个元素相关状态并将其压缩成2进制数就可以达 ...

  8. FZU 1025 状压dp 摆砖块

    云峰菌曾经提到过的黄老师过去讲课时的摆砖块 那时百度了一下题目 想了想并没有想好怎么dp 就扔了 这两天想补动态规划知识 就去FZU做专题 然后又碰到了 就认真的想并且去做了 dp思想都在代码注释里 ...

  9. HDU 3920Clear All of Them I(状压DP)

    HDU 3920   Clear All of Them I 题目是说有2n个敌人,现在可以发n枚炮弹,每枚炮弹可以(可以且仅可以)打两个敌人,每一枚炮弹的花费等于它所行进的距离,现在要消灭所有的敌人 ...

随机推荐

  1. 交互式脚本expect场景示例

    expect语法示例 #spawn 新建一个进程,这个进程的交互由expect控制 #expect 等待接受进程返回的字符串,直到超时时间,根据规则决定下一步操作 #send 发送字符串给expect ...

  2. fatal: unable to connect to github.com npm install fail问题

    解决方法 git config --global url."https://".insteadOf git://

  3. python爬虫爬取天气数据并图形化显示

    前言 使用python进行网页数据的爬取现在已经很常见了,而对天气数据的爬取更是入门级的新手操作,很多人学习爬虫都从天气开始,本文便是介绍了从中国天气网爬取天气数据,能够实现输入想要查询的城市,返回该 ...

  4. SQLI-LABS LESS 1-LESS 22

    SQLI-LABS LESS 1-LESS 22 0x01:前言 因为最近感觉手注快忘光了,所以玩一遍sqli-labs巩固一下. sql注入,基于从服务器接收到的响应分类为 : ▲基于错误的SQL注 ...

  5. 转 根据CPU核心数确定线程池并发线程数

    转自: https://www.cnblogs.com/dennyzhangdd/p/6909771.html?utm_source=itdadao&utm_medium=referral 目 ...

  6. 浅谈Python设计模式 - 原型模式

    声明,本系列文章主要参考<精通Python设计模式>一书,并且参考一些资料,结合自己的一些看法来总结而来. 在<精通Python设计模式>中把设计模式分为三种类型: 创建型模式 ...

  7. zabbix--自定义监控项vsftpd

    Zabbix 自定义监控项之监控 vsftpd zabbix 提供了很多监控选择,功能丰富,我们还可以根据自定义来监控想要监控一些日常的服务等. 说明: 此处我们通过监控 ftp (自定义命令),实现 ...

  8. 【使用DIV+CSS重写网站首页案例】CSS浮动

    CSS浮动: 浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边缘为止 由于浮动框不在文件的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样. 选择器之 float属性 ...

  9. C程序回顾

    1.字符串操作 C中,字符串以一维数组的方式存储.字符串结束标志\0,可用scanf("%s",c);输入,以空格作为输入字符串之间的分隔符. 字符串处理函数:puts(str); ...

  10. dfs 全排列 使用交换——含重复元素和非重复元素

    15. 全排列 中文 English 给定一个数字列表,返回其所有可能的排列. 样例 样例 1: 输入:[1] 输出: [ [1] ] 样例 2: 输入:[1,2,3] 输出: [ [1,2,3], ...