首页 > 其他分享 >AtCoder Regular Contest 109 F 1D Kingdom Builder

AtCoder Regular Contest 109 F 1D Kingdom Builder

时间:2023-04-20 13:33:07浏览次数:43  
标签:Kingdom AtCoder 被删 int long 109 maxn mems 棋子

洛谷传送门

AtCoder 传送门

考虑判断一个终止态是否可达。如果只有一个棋子连续段那一定可达;否则就存在 \(\ge 2\) 个连续段。此时把放棋子看成删除,那么限制就是如果删除一个孤立的棋子(两边没有棋子)且还有别的格子有棋子,这个棋子的颜色 异于其他连续段的两边棋子的颜色

设第一个被删的段(最后一个放棋子的段)的最后一个棋子颜色为 \(c\),记其补色为 \(c'\)。想删掉这个棋子就必须把其他连续段删成两边都是 \(c'\)。借这个机会可以把所有包含 \(c\) 的段都删除,剩下的段只会包含 \(c'\)。这样的段最多只有一个(多了就寄了),所以这个段就是最后被删除的段(第一个放棋子的段)。

可以发现删棋子和放棋子的方案是一一对应的,所以“存在一个合法的删棋子方案”就是“存在一个合法的放棋子方案”的充要条件。

考虑枚举 \(c\),那么根据以上讨论有如下限制:

  • 第一个被删的段必须包含子序列 \(c\)。
  • 最后被删的段 和它两边 必须包含子序列 \(c'c'\)。
  • 其他段 和它两边 必须包含子序列 \(c'cc'\)。

考虑左边和右边扩充 \(3\) 位后大力 dp。设 \(f_{i,0/1,0/1}\) 表示钦定 \(i\) 不放棋子,当前是否存在 第一个被删的段 ,当前是否存在 最后被删的段 ,放棋子数量的最小值。转移大概是如果 \(i-1\) 不放棋子就是 \(f_{i,x,y} \gets f_{i-1,x,y}\),否则枚举 \(i-1\) 所在段的左端点,考虑这一段是第一个被删的段、最后被删的段还是其他段。

直接做是 \(O(n^2)\) 的,考虑优化。容易通过子序列自动机找到以 \(i-1\) 为右端点的第一个合法的左端点,并且发现能转移的点是一段前缀。分三类记一下前缀最小值即可。这样是 \(O(n)\) 的。

code
// Problem: F - 1D Kingdom  Builder
// Contest: AtCoder - AtCoder Regular Contest 109
// URL: https://atcoder.jp/contests/arc109/tasks/arc109_f
// 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 long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 100100;

int n, a[maxn], b[maxn], pre[maxn][2];
int f[maxn][2][2], fa[2], fb[2], fc[2][2];
char s[maxn], t[maxn];

inline int work(int c) {
	mems(f, 0x3f);
	mems(fa, 0x3f);
	mems(fb, 0x3f);
	mems(fc, 0x3f);
	f[1][0][0] = 0;
	for (int i = 2, ja = 1, jb = 1, jc = 1; i <= n; ++i) {
		if (b[i]) {
			continue;
		}
		while (pre[i + 1][c ^ 1] && ja <= pre[pre[i + 1][c ^ 1] - 1][c ^ 1]) {
			for (int x = 0; x <= 1; ++x) {
				fa[x] = min(fa[x], f[ja][0][x] - ja);
			}
			++ja;
		}
		while (jb < pre[i][c]) {
			for (int x = 0; x <= 1; ++x) {
				fb[x] = min(fb[x], f[jb][x][0] - jb);
			}
			++jb;
		}
		while (jc <= pre[pre[pre[i + 1][c ^ 1]][c]][c ^ 1]) {
			for (int x = 0; x <= 1; ++x) {
				for (int y = 0; y <= 1; ++y) {
					fc[x][y] = min(fc[x][y], f[jc][x][y] - jc);
				}
			}
			++jc;
		}
		// printf("i: %d %d %d %d\n", i, ja, jb, jc);
		f[i][0][0] = min(f[i - 1][0][0], fc[0][0] + i - 1);
		f[i][1][0] = min(f[i - 1][1][0], min(fc[1][0], fa[0]) + i - 1);
		f[i][0][1] = min(f[i - 1][0][1], min(fc[0][1], fb[0]) + i - 1);
		f[i][1][1] = min(f[i - 1][1][1], min({fc[1][1], fa[1], fb[1]}) + i - 1);
		// printf("i: %d %d %d %d %d\n", i, f[i][0][0], f[i][1][0], f[i][0][1], f[i][1][1]);
	}
	return f[n][1][1];
}

void solve() {
	scanf("%d%s%s", &n, s + 4, t + 4);
	for (int i = 4; i <= n + 3; ++i) {
		a[i] = (s[i] == 'b');
		b[i] = (t[i] == 'o');
	}
	a[n + 4] = a[n + 5] = a[n + 6] = 1;
	n += 6;
	pre[1][0] = pre[1][1] = 0;
	for (int i = 2; i <= n + 1; ++i) {
		for (int j = 0; j <= 1; ++j) {
			pre[i][j] = pre[i - 1][j];
		}
		pre[i][a[i - 1]] = i - 1;
	}
	int l = -1, r = -1;
	for (int i = 1; i <= n; ++i) {
		if (b[i]) {
			if (l == -1) {
				l = i;
			}
			r = i;
		}
	}
	printf("%d\n", min({r - l + 1, work(0), work(1)}));
}

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

标签:Kingdom,AtCoder,被删,int,long,109,maxn,mems,棋子
From: https://www.cnblogs.com/zltzlt-blog/p/17336473.html

相关文章

  • AtCoder Beginner Contest 298
    A-JobInterview#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn; strings; cin>>n>>s; if(s.find("x")!=-1){ printf("No\n"); }elseif(s.find("o")==-1){ printf("No......
  • Atcoder Regular Contest 118 E - Avoid Permutations(容斥+DP)
    挺套路的DP。第一步是显然的:转换贡献体,DP一条从\((0,0)\)到\((n+1,n+1)\)的路径,然后计算有多少个排列满足这条路径不经过任何一个\((i,p_i)\)。正着统计肯定不好求,考虑容斥。即我们钦定一些路径上的点,满足这些点必须对应某个\((i,p_i)\),然后计算有多少个\(p\)符合这个......
  • AtCoder Regular Contest 109 E 1D Reversi Builder
    洛谷传送门AtCoder传送门考虑固定\(s\)和每个格子的颜色,最终有多少个石子被染黑。结论:任何时刻只有不多于两个极大同色连通块。证明:设\([x,y]\)为当前的黑连通块,\([y+1,z]\)为白连通块。如果下一次染\(x-1\),若\(x-1\)为白,则\([x-1,z]\)都被染为白;否则\(x-1\)被......
  • PAT Basic 1109. 擅长C
    PATBasic1109.擅长C1.题目描述:当你被面试官要求用C写一个“HelloWorld”时,有本事像下图显示的那样写一个出来吗?2.输入格式:输入首先给出26个英文大写字母A-Z,每个字母用一个\(7×5\)的、由C和.组成的矩阵构成。最后在一行中给出一个句子,以回车结束。句子是由......
  • AtCoder Regular Contest 109 D L
    洛谷传送门AtCoder传送门这种题根本做不出来……考虑一个L形怎么方便地表示出来。可以发现对于组成L形的三个点\((x_1,y_1),(x_2,y_2),(x_3,y_3)\),只要知道\(x=x_1+x_2+x_3\)和\(y=y_1+y_2+y_3\),就能确定三个坐标。证明是设折点坐标为\((p,q)\),则其余两......
  • AtCoder Regular Contest 106 F Figures
    洛谷传送门AtCoder传送门晚自习的时候胡出来的做法(((首先你会发现题目等价于求\(\sum\limits_{(\sum\limits_{i=1}^na_i)=2(n-1)\land\foralli\in[1,n],1\lea_i\led_i}\prod\limits_{i=1}^n\dfrac{d_i!}{(d_i-a_i)!}\)。翻译一下就是枚举每个点的度数\(a_i\)......
  • ABC297F AtCoder Beginner Contest 297 F - Minimum Bounding Box 2
    https://atcoder.jp/contests/abc297/tasks/abc297_f在\(n\timesm\)的棋盘上放置\(k\)个棋子,记矩形A为能覆盖所有\(k\)个棋子的最小的矩形,求A的面积的期望将问题反过来考虑,枚举每种矩形有多少种放置棋子的方案,对于一个\(n\timesm\)的矩形,我们可以用容斥的方法......
  • AtCoder Beginner Contest 295
    ThreeDaysAgo我们定义一个只由数字构成的字符串中的字符能够被重排成相同的两份,我们称这个字符串是个好字符串,比如12341234现在给定一个字符串\(S\),找出所有的\([l,r]\),使得在这段区间中的子段是个好字符串题解:思维+组合计数首先我们根据题意得到:一个好字符串中所有相......
  • Atcoder题解:Agc002_f
    我们可以把这个理解成一种类似卡塔兰数的形式,我们发现,被安排的\(0\)球总数\(i\)和已经出现的颜色种数\(j\)在任意时刻都必须满足\(i\gej\)。然后就可以\(dp\)了,我们每次钦定下一个转移的球是某种颜色。如果下一个转移的球不是\(0\),那么我们就一次性把后面所有这种颜色......
  • Atcoder题解:Agc004_e
    \[吓死我了,还以为写了半天的被自己删掉了\]\[但是\text{Ctrl+S}会保存草稿啊\]\[以后一定要保留这个好习惯\]第一步转化题意,我们把“所有机器人移动”转化成“出口带着边框移动”,而在出口运动过程中超出边框的机器人,就“死”了。然后我们发现,出口运动过程中,假设出口目前走到......