Atcoder AGC043B(123 Triangle)题解

本文针对一个特定序列进行变换操作,探讨其最终值的规律。通过对序列的性质分析,结合杨辉三角形及组合数学原理,得出高效求解方法。

专门为这题写个题解。

Description

给定一个仅包含1,2,31,2,31,2,3的序列,每次这个序列的长度减111,第iii位上的数变为原来序列中第iii位减去第i+1i+1i+1位的数的绝对值

当这个序列的长度变成111时,唯一那个数的值。

Solution

首先,我们可以发现几个性质:

①经历了第一次变换后,333消失了,000可能会出现。
这个很容易证: 1,2,31,2,31,2,3中任选两个可以相同的数相减的值的绝对值,一定不为333

②答案为000111222
证明方法与①同理。

③如果经历了一次变换后序列中存在111,则答案不能为222
假设第iii个位置为111,在第iii个位置左边的数为000111222。经历了一次变换后,位置为i−1i-1i1的这个数只能是000111,因为∣2−1∣=∣0−1∣=1,∣1−1∣=0|2-1|=|0-1|=1, |1-1|=021=01=1,11=0。扩展到整个序列的情况,222会因为111的存在慢慢消失。

于是,我们先对这个序列做一次变换,并开始大力分讨。


假设当前序列中只有000111。可以发现,最终答案只能是000111

由于a=0/1,b=0/1a=0/1, b=0/1a=0/1,b=0/1时有a+b=∣a−b∣a+b=|a-b|a+b=ab,所以,我们每次的变换相当于"第iii位上的数变为原来序列中第iii加上i+1i+1i+1位的数"。

我们用字母写下这个序列:

a b c d e

经历许多次变换后,序列分别长这样:

a b c d e
a+b b+c c+d d+e
a+2b+c b+2c+d c+2d+e
a+3b+3c+d b+3c+3d+e
a+4b+6c+4d+e

观察一下第一列的数的各项系数,可以发现:这与杨辉三角形有关!

即,假设010101序列为a1,a2,a3……ana_1,a_2,a_3……a_na1,a2,a3an,那么答案就是(∑i=1nCn−1i−1ai) mod 2(\sum_{i=1}^n C_{n-1}^{i-1} a_i)\ mod\ 2(i=1nCn1i1ai) mod 2

假设k!k!k!中质因数222的个数为numknum_knumk,那么CxyC_x^yCxy的质因数222的个数就是numx−numy−numx−ynum_x-num_y-num_{x-y}numxnumynumxy。如果这个值为正,那么就是偶数;否则就是奇数。于是,010101序列的情况就处理完了。


注意到,这个序列中可能还含有222。我们继续大力分讨。

假设这个序列只有000222,显然最终答案只能是000222,不能是111。但是,我们仍然可以将这个序列转化为010101序列的情况。即,我们将这个020202序列中每个数都除以222,变成010101序列;最终的答案为010101序列的答案的两倍。

最后一种情况: 这个序列存在0,1,20,1,20,1,2

可以发现,根据性质③中的"如果经历了一次变换,序列中存在111,则答案不能为222",得到答案只能为000111。于是,我们可以将222变成000,此时转化为010101序列就直接用上述方法去算,最终答案显然不变。


于是,这道神仙题就做完了。时间复杂度O(n)O(n)O(n)

有必要总结一下。这题中,我们可以通过打表思考来发现三个性质,然后将模型简化为010101序列,再扩展为其他情况,最终通过找规律与组合数、数论巧妙地解决了本题。

作为一道AGCAGCAGCBBB题,这是比较难的,但是毫无疑问,本题考查得十分综合,是一道不可多得的好题。

Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxl=1000005;

int n,ans=0;
int a[maxl],b[maxl],c[maxl],with_2[maxl];

int C(int x,int y)
{
	int now=with_2[x]-with_2[x-y]-with_2[y];
	if (now)  return 0;
	else return 1;
}

signed main()
{
	cin>>n;
	for (int i=1;i<=n;i++)
	{
		char x;
		cin>>x;
		a[i]=x-'0';
	}
	if (n<=2)  return cout<<abs(a[1]-a[2])<<endl,0;
	for (int i=1;i<=n-1;i++)  b[i]=abs(a[i]-a[i+1]);
	
	int flag=1;
	for (int i=1;i<=n-1;i++)
	{
		if (b[i]==1)  flag=0;
	}
	if (flag==1)
	{
		for (int i=1;i<=n;i++)  b[i]/=2;
	}
	for (int i=1;i<=n-2;i++)  c[i]=abs(b[i]-b[i+1]);
	n-=2;
	
	for (int i=1;i<=n;i++)
	{
		with_2[i]=with_2[i-1];
		
		int saver=i,cnt=0;
		while (!(saver&1))  saver>>=1,cnt++;
		with_2[i]+=cnt;
	}
	for (int i=1;i<=n;i++)  ans=(ans+C(n-1,i-1)*c[i])%2;
	if (flag==0)  cout<<ans<<endl;
	else if (flag==1)
	{
		if (ans==1)  cout<<2<<endl;
		else cout<<0<<endl;
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值