【10.26校内测试】【状压?DP】【最小生成树?搜索?】
Solution
据说正解DP30行???
然后写了100行的状压DP??
疯狂特判,一算极限时间复杂度过不了aaa!!
然而还是过了....QAQ
所以我定的状态是待转移的位置的前三位,用6位二进制位表示,每2位表示一个位置的状态。然后特判转移就可以了QAQ
Code
#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
#define RG register
using namespace std; char fi[];
int a[];
LL dp[][];
int len; int change(char x) {
if(x == '?') return ;
if(x == '*') return ;
if(x == '') return ;
if(x == '') return ;
if(x == '') return ;
} bool check(int s, int i) {
int pre = s & ( << );
int s1 = s >> , s2 = (s ^ pre) >> , s3 = s & ;
if(~a[i] && a[i] != && s3 != a[i]) return ;
if(i - > && a[i - ] != && s2 != a[i - ]) return ;
if(i - > && a[i - ] != && s1 != a[i - ]) return ;
if(i == len) {
if(s3 == && s2 != ) return ;
if(s3 == ) return ;
if(s3 == && s2 == ) return ;
}
if(i == ) {
if(s1 || s2) return ;
if(s3 == ) return ;
return ;
} else if(i == ) {
if(s1) return ;
if(s2 == && s3 == ) return ;
if(s2 == && s3 != ) return ;
if(s2 == ) return ;
if(s2 == && s3 == ) return ;
if(s3 == && s2 != ) return ;
return ;
}
if(s1 == && s2 == ) return ;
if(s1 == && s2 == ) return ;
if(s1 == && s2 != ) return ;
if(s1 == && s2 == ) return ;
if(s2 == && (s1 == || s3 == )) return ;
if(s2 == && s1 == && s3 == ) return ;
if(s2 == && (s1 != && s3 != )) return ;
if(s2 == && (s1 != || s3 != )) return ;
if(s2 == && (s1 == || s3 == )) return ;
if(s3 == && s2 == ) return ;
if(s3 == && s2 == ) return ;
if(s3 == && s2 != ) return ;
if(s3 == && s2 == ) return ;
return ;
} int main() {
freopen("mine.in", "r", stdin);
freopen("mine.out", "w", stdout);
scanf("%s", fi + );
len = strlen(fi + );
if(len == ) {
if(fi[] == '' || fi[] == '?') puts("");
else puts("");
return ;
}
memset(a, -, sizeof(a));
for(int i = ; i <= len; i ++)
a[i] = change(fi[i]);
int now = ;
if(a[] != ) {
dp[now][a[]] = ;
} else dp[now][] = dp[now][] = dp[now][] = dp[now][] = ;
for(RG int i = ; i <= len; i ++) {
now ^= ;
memset(dp[now], , sizeof(dp[now]));
for(RG int s = ; s < ( << ); s ++) {
int pre = s & ( << );
if(!check(s, i - )) continue;
if(a[i] != ) {
int ss = (s ^ pre) << | a[i];
if(!check(ss, i)) continue;
dp[now][ss] = (dp[now ^ ][s] + dp[now][ss]) % mod;
} else {
for(RG int k = ; k <= ; k ++) {
int ss = (s ^ pre) << | k;
if(!check(ss, i)) continue;
dp[now][ss] = (dp[now ^ ][s] + dp[now][ss]) % mod;
}
}
}
}
LL ans = ;
for(int s = ; s < ( << ); s ++)
if(check(s, len)) ans = (ans + dp[now][s]) % mod;
printf("%lld", ans);
return ;
}
Solution
完全把题意理解错了QAQ
以为从每一个点开始一直就只能向上下左右四个方向走了QAQ
结果一波暴力还得了20pts??
正解不懂QAQ然而$zyl$dalao爆搜轻松过!
其实也不是很暴力的搜辣,加上记忆化剪枝,大大的好!
先预处理出可以流出去的位置们,然后对于每一个位置暴力bfs它们的所有路径QAQ,记忆化剪枝效果非常好了QAQ
很有道理的样子呢QAQ
我们要找的实际上就是每个点出去的每条路径上最大值的最小值,而想到最小生成树就是满足这个性质,最大边最小。
所以按边权排序加边,两个联通块中如果一个已经有出去的节点,另一个没有,那么更新没有的那个联通块的答案就是这条新加的边权。
吼麻烦啊QAQ
#include<bits/stdc++.h>
using namespace std; int h[][], n, m;
int dx[] = {, , , -}, dy[] = {, -, , }; inline void read(int &x) {
x = ; int t = ; char ch = getchar();
while(ch > '' || ch < '') { if(ch == '-') t = -; ch = getchar(); }
while(ch >= '' && ch <= '') { x = x * + ch - ''; ch = getchar(); }
x *= t;
} bool check(int x, int y) {
return x >= && y >= && x <= n + && y <= m + ;
} int vis[][], vis1[][], ans[][];
int idc, tmp;
void dfr(int x, int y) {
if(vis[x][y]) return ;
vis[x][y] = ;
for(int k = ; k < ; k ++) {
int xx = x + dx[k], yy = y + dy[k];
if(!check(xx, yy)) ans[x][y] = ;
else if(h[xx][yy] <= h[x][y]) {
dfr(xx, yy);
if(ans[xx][yy] == ) ans[x][y] = ;
}
}
} bool dfs(int x, int y, int u) {
if(vis1[x][y] == idc) return ;
if(h[x][y] > u) {
tmp = min(tmp, h[x][y] + ans[x][y]);
return ;
}
if(ans[x][y] == ) return ;
vis1[x][y] = idc;
for(int k = ; k < ; k ++) {
int xx = x + dx[k], yy = y + dy[k];
if(!dfs(xx, yy, u)) return ;
}
return ;
} struct Point {
int x, y, h;
bool operator < (const Point &t) const {
return h > t.h;
}
} points[ * ]; int main() {
freopen("water.in", "r", stdin);
freopen("water.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++) {
read(h[i][j]);
points[(i - ) * m + j] = (Point) {i, j, h[i][j]};
}
sort(points + , points + + n * m);
memset(ans, -, sizeof(ans));
for(int i = ; i <= n; i ++)
for(int j = ; j <= m; j ++) dfr(i, j);
for(int i = ; i <= n * m; i ++) {
idc ++;
tmp = 0x3f3f3f3f;
if(!dfs(points[i].x, points[i].y, points[i].h))
ans[points[i].x][points[i].y] = ;
else ans[points[i].x][points[i].y] = tmp - points[i].h;
}
for(int i = ; i <= n; i ++) {
for(int j = ; j <= m; j ++) printf("%d ", ans[i][j]);
printf("\n");
}
return ;
}
【10.26校内测试】【状压?DP】【最小生成树?搜索?】的更多相关文章
- 相邻行列相互影响的状态类问题(类似状压dp的搜索)(POJ3279)
POJ3279http://poj.org/problem?id=3279 题意:黑白的板,每次选择一个十字形翻转(十字板内黑白互换,若是边界则不管),求最小将原图变为全白的策略. 这是一道对于每个格 ...
- 【10.5校内测试】【DP】【概率】
转移都很明显的一道DP题.按照不优化的思路,定义状态$dp[i][j][0/1]$表示吃到第$i$天,当前胃容量为$j$,前一天吃(1)或不吃(0)时能够得到的最大价值. 因为有一个两天不吃可以复原容 ...
- 你必须知道的基本位运算技巧(状压DP、搜索优化都会用到)
一. 位操作基础 基本的位操作符有与.或.异或.取反.左移.右移这6种,它们的运算规则如下所示: 符号 描述 运算规则 & 与 两个位都为1时,结果才为1 | 或 两个位都为0时,结果才为0 ...
- [POJ1038]状压DP
题意:给一个n*m的区域,里面有一些障碍物,往里面放2*3和3*2的矩形,矩形之间不能重叠,不能覆盖到障碍物,求能放置的最大个数.(n<=150,m<=10) 思路:看到m=10就应该往状 ...
- 关灯问题II 状压DP
关灯问题II 状压DP \(n\)个灯,\(m\)个按钮,每个按钮都会对每个灯有不同影响,问最少多少次使灯熄完. \(n\le 10,m\le 100\) 状压DP的好题,体现了状压的基本套路与二进制 ...
- 【62测试】【状压dp】【dfs序】【线段树】
第一题: 给出一个长度不超过100只包含'B'和'R'的字符串,将其无限重复下去. 比如,BBRB则会形成 BBRBBBRBBBRB 现在给出一个区间[l,r]询问该区间内有多少个字符'B'(区间下标 ...
- tyvj 2054 [Nescafé29]四叶草魔杖——最小生成树+状压dp
题目:http://www.joyoi.cn/problem/tyvj-2054 枚举点集,如果其和为0,则作为一个独立的块求一下最小生成树.因为它可以不和别的块连边. 然后状压dp即可. 别忘了判断 ...
- [tyvj2054] 四叶草魔杖 (最小生成树 状压dp)
传送门 Background 陶醉在彩虹光芒笼罩的美景之中,探险队员们不知不觉已经穿过了七色虹,到达了目的地,面前出现了一座城堡和小溪田园,城堡前的木牌上写着"Poetic Island&q ...
- 2018.12.26 考试(哈希,二分,状压dp)
T1 传送门 解题思路 发现有一个限制是每个字母都必须相等,那么就可以转化成首尾的差值相等,然后就可以求出\(k-1\)位的差值\(hash\)一下.\(k\)为字符集大小,时间复杂度为\(O(nk) ...
随机推荐
- Tslib步骤以及出现问题的解决方案【转】
转自:http://forum.eepw.com.cn/thread/267828/1 嵌入式设备中触摸屏使用非常广泛,但触摸屏的坐标和屏的坐标是不对称的,需要校准.校准广泛使用的是开源的tslib. ...
- 2015 Dhaka
2015 Dhaka A - Automatic Cheater Detection solution 模拟计数. B - Counting Weekend Days solution 模拟计数. C ...
- 利用github pages五分钟建好个人网站+个人博客
笔者自己在建个人网站/个人博客的时候其实遇到了不少麻烦,但是都一一解决了,这里教给大家最简单的方式. 首先你需要一个GitHub账号,访问https://github.com创建新账号即可. 然后访问 ...
- poj1095
题意:给出n,要求输出第n个二叉树,二叉树编号规则如下图所示: 分析:g[i]表示有i个节点的二叉树,有多少种.f[i][j]表示有i个节点,且左子树有j个节点的树有多少种. sumg[i]表示g数组 ...
- pycharm tornado 项目 配置
ycharm 配置tornado项目 使得能够像django项目一样运行
- 详述Java对象创建
Java是一门面向对象的语言,Java程序运行过程中无时无刻都有对象被创建出来.在语言层面上,创建对象(克隆.反序列化)就是一个new关键字而已,但是虚拟机层面上却不是如此.我们看一下在虚拟机层面上创 ...
- 洛谷P1972 HH的项链
传送门啦 分析: 题目描述不说了,大意是,求一段区间内不同元素的种数. 看到区间,我们大概先想到的是暴力(然后炸掉).线段树.树状数组.分块. 下面给出的是一种树状数组的想法. 首先,对于每一段区间里 ...
- java多线程-读写锁原理
Java5 在 java.util.concurrent 包中已经包含了读写锁.尽管如此,我们还是应该了解其实现背后的原理. 读/写锁的 Java 实现(Read / Write Lock Java ...
- Linux下LAMP服务器的搭建
1.安装并配置Apache 安装apache的方法有很多种,这里选择通过yum方式进行安装,但需要Linux系统能够连接互联网,执行如下命令,安装Apache. # yum install httpd ...
- VS Code折腾记 - (1)扯淡
题外话 距离上篇介绍VSCode的文章已经过去四十多天,已经在正式项目作为主力开发工具了. 社区的发展非常快速,更新迭代够快,功能基本已经满足我所需了: 这个系列教程基于最新的vs code 1.8. ...