首页 > 其他分享 >AtCoder Beginner Contest 296 Ex Unite

AtCoder Beginner Contest 296 Ex Unite

时间:2023-06-28 20:44:20浏览次数:43  
标签:AtCoder typedef Beginner Contest int long maxn mp find

洛谷传送门

AtCoder 传送门

不错的 dp。

考虑按行从上往下 dp,并且把列的连通状态塞进 dp 状态里面。实际上就是塞一个并查集。

判状态合法性就是当一个竖的全黑长条结束后,有没有跟别的列连起来。

code
// Problem: Ex - Unite
// Contest: AtCoder - AtCoder Beginner Contest 296
// URL: https://atcoder.jp/contests/abc296/tasks/abc296_h
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;
typedef vector<int> vi;

const int maxn = 140;

int n, m, ntot, fa[maxn], g[maxn], f[maxn][maxn][500];
char s[maxn][maxn];
map<vi, int> mp;
vi pm[500];
bool vis[10];

inline int ID(vi v) {
	if (mp.find(v) != mp.end()) {
		return mp[v];
	} else {
		++ntot;
		pm[ntot] = v;
		return mp[v] = ntot;
	}
}

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline void merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
	}
}

void solve() {
	scanf("%d%d", &n, &m);
	int L = 1e9, R = -1;
	for (int i = 1; i <= n; ++i) {
		scanf("%s", s[i]);
		for (int j = 0; j < m; ++j) {
			if (s[i][j] == '#') {
				L = min(L, i);
				R = max(R, i);
			}
		}
	}
	if (R == -1) {
		puts("0");
		return;
	}
	vi t;
	for (int i = 0; i < m; ++i) {
		t.pb(i);
	}
	mems(f, 0x3f);
	f[L - 1][0][ID(t)] = 0;
	for (int i = L; i <= R; ++i) {
		for (int S = 0; S < (1 << m); ++S) {
			for (int j = 1; j <= ntot; ++j) {
				if (f[i - 1][S][j] > 1e9) {
					continue;
				}
				int sta = 0;
				for (int k = 0; k < m; ++k) {
					if (s[i][k] == '#') {
						sta |= (1 << k);
					}
				}
				for (int T = sta; T < (1 << m); T = (T + 1) | sta) {
					bool flag = 0;
					mems(vis, 0);
					for (int k = 0; k < m; ++k) {
						if ((S & T) & (1 << k)) {
							vis[pm[j][k]] = 1;
						}
					}
					for (int k = 0; k < m; ++k) {
						if ((S & (1 << k)) && !vis[pm[j][k]]) {
							flag = 1;
							break;
						}
					}
					if (flag) {
						continue;
					}
					for (int k = 0; k < m; ++k) {
						fa[k] = k;
					}
					for (int x = 0; x < m; ++x) {
						for (int y = x + 1; y < m; ++y) {
							if (pm[j][x] == pm[j][y] && (S & (1 << x)) && (S & (1 << y)) && (T & (1 << x)) && (T & (1 << y))) {
								merge(x, y);
							}
						}
					}
					for (int k = 0; k + 1 < m; ++k) {
						if ((T & (1 << k)) && (T & (1 << (k + 1)))) {
							merge(k, k + 1);
						}
					}
					for (int k = 0; k < m; ++k) {
						g[k] = m;
					}
					for (int k = 0; k < m; ++k) {
						int x = find(k);
						g[x] = min(g[x], k);
					}
					vi v;
					for (int k = 0; k < m; ++k) {
						v.pb(g[find(k)]);
					}
					int nj = ID(v);
					f[i][T][nj] = min(f[i][T][nj], f[i - 1][S][j] + __builtin_popcount(T ^ sta));
				}
			}
		}
	}
	int ans = 1e9;
	for (int S = 0; S < (1 << m); ++S) {
		for (int i = 1; i <= ntot; ++i) {
			if (f[R][S][i] > 1e9) {
				continue;
			}
			int cnt = 0;
			for (int j = 0; j < m; ++j) {
				if (pm[i][j] == j && (S & (1 << j))) {
					++cnt;
				}
			}
			if (cnt == 1) {
				ans = min(ans, f[R][S][i]);
			}
		}
	}
	printf("%d\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,typedef,Beginner,Contest,int,long,maxn,mp,find
From: https://www.cnblogs.com/zltzlt-blog/p/17512529.html

相关文章

  • AtCoder Beginner Contest 227 H Eat Them All
    洛谷传送门AtCoder传送门好奇特的题。考虑显式建图,那么这是一个\(9\)个结点,\(12\)条边的图,需要找到一条回路使得第\(i\)个点被经过\(a_i\)次。首先会有一个基本思路:先求出每条边经过的次数,然后每条边复制这么多次即可直接构造欧拉回路。其中每条边经过次数的限制就是,......
  • AtCoder Beginner Contest 306(ABC 306) E~F补题
    E题目大意给定数字$k$,规定数组$A$的函数$f(A)$:$A$数组前$k$大数字的和如$A=[1,3,7,~4]$,$k=2$,则$f(A)=7+4=11$现在给定最大数组长度$n$,有$q$组操作,每次将第$x$个数字修改为$y$,输出每次操作后的$f(A)$其中$0<k\leqn\leq5\times10^5,~q\leq5\times......
  • AtCoder Beginner Contest 228 G Digits on Grid
    洛谷传送门AtCoder传送门?这啥啊,不会。考虑行和列分别作为左部点和右部点建二分图(实际上这个建图只是辅助理解,不需要显式建图),每个左部点和每个右部点,边权为格子中的数。容易想到一个dp,设\(f_{i,j}\)为走了\(i\)步,当前在点\(j\),走过的所有边权组成的不同整数的数量。但......
  • AtCoder Beginner Contest 072
    A-Sandglass2#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongint32_tmain(){inta,b;cin>>a>>b;cout<<max(a-b,0ll);return0;}B-OddString#include<bits/stdc++.h>......
  • AtCoder Beginner Contest 238 Ex Removing People
    洛谷传送门AtCoder传送门考虑期望转计数,方案数显然是\(n!\)(第\(i\)次操作有\(n-i+1\)个人可供选择),所以问题转化为求所有方案的代价之和。考虑倒着做,变成先放一个人,然后依次放\(n-1\)个人,每次放的这个人可以让左边的人的\(S\)变成R,代价是他与他左边的人的距离,......
  • AtCoder Beginner Contest 307 Ex Marquee
    洛谷传送门AtCoder传送门一开始看错题了,看了好久才发现就是个板子。。。这个东西本质上是循环移位,我们考虑在\(S\)前后各添加\(W-1\)个.,例如\(W=5,S=\texttt{ABC}\)时,添加后\(S=\texttt{....ABC....}\)。此时我们发现\(S\)的每个长度为\(W\)的子串一一对......
  • AtCoder Beginner Contest(abc) 307
    A-WeeklyRecords题目大意小莫每天跑步,输入n周每天的步数,输出每周跑的总步数;解题思路签到题不多嗦了;神秘代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m,k,idx;signedmain(){ cin>>n; intsum=0; for(inti......
  • AtCoder Beginner Contest 307 G Approximate Equalization
    洛谷传送门AtCoder传送门考虑我们如果确定了最终态\(B=(B_1,B_2,...,B_n)\),如何计算最少操作次数。显然从左往右依次使\(A_i=B_i\)。当操作到第\(i\)个位置时,此时\(A'_i=\sum\limits_{j=1}^iA_j-B_j\),所需操作次数为\(|A'_i|\)。令\(C_i=\sum\limits_{......
  • AtCoder Beginner Contest 245 Ex Product Modulo 2
    洛谷传送门AtCoder传送门很好的题。下文令\(k\)为原题面中的\(n\),\(n\)为原题面中的\(k\),\(m\)为原题面中的\(m\)。从一些简单的情况入手。1.\(m\)为质数\(k=0\)的情况是平凡的,只需要要求\(\existsi\in[1,n],a_i=0\)即可。总方案数减去不合法方案数,......
  • AtCoder Beginner Contest 307 ABCDE
    AtCoderBeginnerContest307A-WeeklyRecordsProblemStatement题意:告诉你有几个礼拜,问你每个礼拜走的路程和。Solution思路:按题意模拟,每7天加起来就行。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;intmain(){ intn; cin>>n; llsum=......