博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)
阅读量:6268 次
发布时间:2019-06-22

本文共 2230 字,大约阅读时间需要 7 分钟。

题面

1442599-20190107155136958-695780439.png

1442599-20190107155139884-387925377.png

题解

我永远讨厌dp.jpg

搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→。全场都插头dp就我一个状压跑得贼慢……

不难发现我们可以状压,对于每一行,用状态\(S\)表示有哪些格子是已经被上一行推倒了的,那么我们可以枚举本行所有格子的字母情况,然后计算一下这个时候下一行格子被推倒的情况,把这一行的贡献加到下一行就行了。

简单来说就是记一个\(f[pos][S]\)表示第\(pos\)行,格子被推倒的情况为\(S\)时的方案数,\(dp[pos][S]\)为所有方案中推倒树的总数,那么假设一个选字母的方案会使下一行的推倒情况为\(S'\),会使这一行可以推倒\(k\)棵树,则有转移\[f[pos+1][S']+=f[pos][S]\]

\[dp[pos+1][S']+=f[pos][S]+k\times f[pos][S]\]
最后\(f[n+1][0]\)就是答案。这样的话能有\(40\)分(建议先看一下40分代码不然看不太懂AC代码的……)

//minamoto#include
#define R register#define fp(i,a,b) for(R int i=a,I=b+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)using namespace std;const int N=13,M=35,L=(1<<21)+5;int a[N][M],f[N][L],dp[N][L],g[N][L],n,m,P,lim,ans,vis[N];inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}void solve(int pos){ fp(i,0,lim-1)if(f[pos][i]){ fp(j,0,lim-1){ int S=0,res=0; fp(k,0,m-1)vis[k]=i&(1<

然后我们发现复杂度高的主要原因是因为行数太多,不过列数很少,那么我们可以对列进行状压。然而这样的话会不符合推倒的顺序。

我们考虑每一条副对角线,这条副对角线上肯定是从右上到左下的推倒顺序,于是我们可以对每一条副对角线进行状压,因为副对角线上元素个数为\(min(n,m)\),所以时间复杂度没问题

信心满满的交上去结果只有\(70\)分,因为按上面那种方式枚举行的推倒情况和行的字母不太好,对于那些已经被推倒的格子,它们不管怎么选都没有影响,所以我们可以只枚举那些没有被推倒的格子,那些已经被推倒的格子直接把贡献加上去就可以了,这样的话复杂度就是\(O(3^n\times\)乱七八糟的常数\()\)

还是一句话,注意细节

//minamoto#include
#define R register#define fp(i,a,b) for(R int i=a,I=b+1;i
I;--i)#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)using namespace std;const int N=55,M=35,L=(1<<12)+5;int a[N][M],f[N][L],dp[N][L],n,m,P,ans,vis[N];int id[N][M],sz[L],bin[N];inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}void solve(int pos){ int cnt=pos-max(0,pos-n)-max(0,pos-m); int stx,sty,edx,edy,dx,dy; if(pos<=m)stx=pos,sty=1; else stx=m,sty=pos-m+1; if(pos<=n)edx=1,edy=pos; else edx=pos-n+1,edy=n; int qaq=pos+1>m,c=pos+1-max(0,pos+1-n)-max(0,pos+1-m); int lim=(1<
>1]+(i&1); bin[0]=1;fp(i,1,30)bin[i]=mul(bin[i-1],2); f[1][0]=1,dp[1][0]=0; fp(i,1,n+m-2)solve(i); printf("%d\n",mul(add(dp[n+m-1][0],dp[n+m-1][1]),2));}

转载于:https://www.cnblogs.com/bztMinamoto/p/10233864.html

你可能感兴趣的文章
SDUT 3503 有两个正整数,求N!的K进制的位数
查看>>
【.Net】C# 根据绝对路径获取 带后缀文件名、后缀名、文件名、不带文件名的文件路径...
查看>>
Redis常用命令速查 <第二篇>
查看>>
CSS规范
查看>>
使用FastDateFormat来代替JDK自带的DateFormat
查看>>
Python爬虫从入门到放弃(十六)之 Scrapy框架中Item Pipeline用法
查看>>
Android源代码解析之(三)--&gt;异步任务AsyncTask
查看>>
(zhuan) 自然语言处理中的Attention Model:是什么及为什么
查看>>
C#中使用RabbitMQ收发队列消息
查看>>
Hadoop1.2.1 全然分布式集群搭建实操笔记
查看>>
第三百二十七节,web爬虫讲解2—urllib库爬虫—基础使用—超时设置—自动模拟http请求...
查看>>
MVC总结--MVC简单介绍以及和WebForm差别
查看>>
tiny4412 裸机程序 五、控制icache【转】
查看>>
VB.NET多线程入门
查看>>
国外物联网平台初探(二) ——微软Azure IoT
查看>>
findlibrary returned null产生的联想,Android ndk开发打包时我们应该怎样注意平台的兼容(x86,arm,arm-v7a)...
查看>>
Android事件分发机制源代码分析
查看>>
《设计模式》结构型模式
查看>>
[javase学习笔记]-8.3 statickeyword使用的注意细节
查看>>
Spring集成RabbitMQ-使用RabbitMQ更方便
查看>>