【10.26校内测试】【状压?DP】【最小生成树?搜索?】

时间:2023-03-10 03:21:11
【10.26校内测试】【状压?DP】【最小生成树?搜索?】

【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 ;
}

【10.26校内测试】【状压?DP】【最小生成树?搜索?】

【10.26校内测试】【状压?DP】【最小生成树?搜索?】

Solution

完全把题意理解错了QAQ

以为从每一个点开始一直就只能向上下左右四个方向走了QAQ

结果一波暴力还得了20pts??

正解不懂QAQ然而$zyl$dalao爆搜轻松过!

其实也不是很暴力的搜辣,加上记忆化剪枝,大大的好!

先预处理出可以流出去的位置们,然后对于每一个位置暴力bfs它们的所有路径QAQ,记忆化剪枝效果非常好了QAQ

【10.26校内测试】【状压?DP】【最小生成树?搜索?】

很有道理的样子呢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 ;
}