[AGC055A] ABC Identity 题解

题目描述

给定长度为 (3n (1 le n le 2e5)) 的序列,其中字母 A,B,C 各有 (n) 个。

一个合法序列 (T) 满足以下条件:

  • 其长度为 (3k (1 le k le n))

  • (T_1 = T_2 = ... = T_k)

  • (T_{k + 1} = T_{k + 2} = ... = T_{2k})

  • (T_{2k + 1} = T_{2k + 2} = ... = T_{3k})

  • (T_1, T_{k + 1}, T_{2k + 1}) 互不相同。
    求一个把这个序列分成不多于 (6) 个合法的序列的方案。
    可以证明,一定存在一种合法的划分。

解析

将序列分成等长的 3 段,用桶来记录每一段 A,B,C 个数,枚举 6 种排列 (ABC,ACB,BAC,BCA,CAB,CBA)

等长的 3 段中,第 (i) 段取当前排列的第 (i) 个字母。

取尽量多,也就是三个桶取min

可以证明枚举完以后序列所有字母会被选完。

(k) 种排列就划分到第 (k) 组。

排列只有 6 种,当然也只有 6 组。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 6e5 + 9;
int n,l,r,mid,ans[N];
char a[N],ck[7][4]={{'0','0','0'},
{'A','B','C'},{'A','C','B'},
{'B','A','C'},{'B','C','A'},
{'C','A','B'},{'C','B','A'}};
int t[4][4];
void input(){
	cin>>n>>a + 1;
	for(int i = 0; i <= 2; ++i){
		for(int j = i * n + 1; j <= (i + 1) * n; ++j){
			++t[i][a[j] - 'A']; 
		}
	}
}
void cg(int num, int cd){
	for(int i = 0; i <= 2; ++i){
		int now = num;
		for(int j = i * n + 1; j <= (i + 1) * n && now; ++j){
			if(ck[cd][i] == a[j] && (!ans[j]))
				ans[j] = cd, --now;
		}
	}
}
void op(){
	for(int i = 1; i <= 6; ++i){
		int num = min(t[0][ck[i][0] - 'A'], min(t[1][ck[i][1] - 'A'], t[2][ck[i][2] - 'A']));
		cg(num, i);
		t[0][ck[i][0] - 'A'] -= num;
		t[1][ck[i][1] - 'A'] -= num;
		t[2][ck[i][2] - 'A'] -= num;
	}
}
int main(){
	cin.tie(0)->sync_with_stdio(0);
	input();
	op();
	for(int i = 1; i <= 3 * n; ++i)
		cout<<ans[i];
}
内容来源于网络如有侵权请私信删除

文章来源: 博客园

原文链接: https://www.cnblogs.com/hfjh/p/17480192.html

你还没有登录,请先登录注册
  • 还没有人评论,欢迎说说您的想法!