AT_arc117_c 题解

文章讲述了在编程竞赛中解决一个关于颜色变换的问题,通过观察和推导,提出了一种方法,利用3的幂性质减少模拟次数,确保顶端颜色仅与底端左右端点相关。作者提供了代码实现和证明过程。
摘要由CSDN通过智能技术生成

题目链接

前言

今天早上模拟赛刚考这题,考场虽然写出来(思路和其他题解好像不太一样),但是不太会证明,若题解有不当之处或者代码可以被举出反例,请及时联系 @guozhetao 改正。

思路

本题解定义 b h ( i , j ) bh(i,j) bh(i,j) 为将第 i i i 个点与第 j j j 个点依据题意变换(如果颜色相同,则为它们的相同颜色;如果颜色不同,则为一个颜色与它们都不同的颜色)。

因为 2 ≤ n ≤ 400000 2 \le n \le 400000 2n400000,因此直接模拟肯定过不了。

观察样例:

W
BR
RWB
RRBB

可以发现最上方的 W 根据题意是由 BR 组合而成,而最低下一行的左右两边分别是 BR

考场上,我尝试其他几种情况,发现当最后一行个数是 4 4 4 时,顶端的字母只和底端左右两个端点有关(且刚好与题目所提供的变化方式相同),于是我猜想:当最后一行个数为 3 k + 1 3^k + 1 3k+1 时,顶端只和底端左右端点有关。

于是,我们每次对于 n n n,找到最大的 k k k 使得 3 k + 1 ≤ n 3^k + 1 \leq n 3k+1n,并枚举第 n − 3 k n - 3 ^ k n3k 层的情况:当 ( i + 3 k ≤ n ) (i + 3 ^ k \leq n) (i+3kn) 时依次更新 b i = b h ( i , i + 3 k ) b_i = bh(i,i + 3^k) bi=bh(i,i+3k),则此时我们将一个长度为 n n n 的序列变为一个长度为 n − 3 k n - 3^k n3k 的序列,然后将 n ← n − 3 k n \gets n - 3^k nn3k。重复以上操作直至 n < 4 n < 4 n<4

操作后若 n ≠ 1 n \not= 1 n=1,因为 n n n 很小,将最后的几行依照题意枚举即可。

代码

记录

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t,n;
char b[400005];
int find(int x) {
	int tot = 1;
	while(x >= 3) {
		x /= 3;
		tot *= 3;
	}
	return tot;
}
signed main() {
	//freopen("B.in","r",stdin);
	//freopen("B.out","w",stdout);
	scanf("%lld",&n);
	for(int i = 1;i <= n;i++) cin >> b[i];
	int ans = n;
	while(ans >= 4) {
		int x = find(ans - 1);//寻找最大的 3^k
        //依题意进行模拟
		for(int i = 1;i + x <= n;i++) {
			if(b[i] == b[i + x]) continue;
			else if(b[i] == 'B' and b[i + x] == 'W') b[i] = 'R';
			else if(b[i] == 'W' and b[i + x] == 'B') b[i] = 'R';
			else if(b[i] == 'W' and b[i + x] == 'R') b[i] = 'B';
			else if(b[i] == 'R' and b[i + x] == 'W') b[i] = 'B';
			else b[i] = 'W';
		}
		ans -= x;
		//printf("%lld\n",ans);
	}
    //最后几行自己模拟
	for(;ans > 1;ans--) {
		for(int i = 1;i < ans;i++) {
			if(b[i] == b[i + 1]) continue;
			else if(b[i] == 'B' and b[i + 1] == 'W') b[i] = 'R';
			else if(b[i] == 'W' and b[i + 1] == 'B') b[i] = 'R';
			else if(b[i] == 'W' and b[i + 1] == 'R') b[i] = 'B';
			else if(b[i] == 'R' and b[i + 1] == 'W') b[i] = 'B';
			else b[i] = 'W';
		}
	}
	cout<<b[1]<<endl;
	return 0;
}

证明过程

因个人能力原因,本部分有参照这篇题解,若无法理解可跳过本部分。

设最底层个数为 m ( m = 3 k + 1 ) m(m = 3 ^ k + 1) m(m=3k+1),若令 B 0 0 0W 1 1 1R 2 2 2,则顶层 p ≡ − ∑ b i × ( m − 1 ) ! i ! × ( m − 1 − i ) ! ( m o d 3 ) p \equiv -\sum b_i \times \dfrac{(m - 1)!}{i! \times (m - 1 - i)!} \pmod 3 pbi×i!×(m1i)!(m1)!(mod3)

由于 m − 1 ≡ 0 ( m o d 3 ) m -1 \equiv 0 \pmod 3 m10(mod3),则当 0 < i < m 0 < i < m 0<i<m 时, ( m − 1 ) ! i ! × ( m − 1 − i ) ! ≡ 0 ( m o d 3 ) \dfrac{(m - 1)!}{i! \times (m - 1 - i)!} \equiv 0 \pmod 3 i!×(m1i)!(m1)!0(mod3);

因此: p ≡ − ∑ b i × ( m − 1 ) ! i ! × ( m − 1 − i ) ! ≡ 6 − b 0 − b m ( m o d 3 ) p \equiv -\sum b_i \times \dfrac{(m - 1)!}{i! \times (m - 1 - i)!} \equiv 6-b_0 - b_m\pmod 3 pbi×i!×(m1i)!(m1)!6b0bm(mod3)

所以当最后一行个数为 3 k + 1 3^k + 1 3k+1 时,顶端只和底端左右端点有关。

  • 40
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值