AT_agc043_b [AGC043B] 123 Triangle 解题报告

  • 不难发现,这道题在从 \(1\)\(n\) 一层一层的不断计算之中,将每层的数放在一起,就形成了一个形状和杨辉三角一样的东西,当然,也有和杨辉三角类似的性质下面会用到
  • 如果你自己手膜了数据的话,会发现 \(3\) 在第二层就已经一定不存在了,因为没有两个数的差值等于 \(3\),所以最后答案只可能是 \(0\),\(1\),\(2\)
  • 继续计算,会发现 \(1\) 无论是遇到 \(0\) 还是 \(2\),最后仍然还是 \(1\),这意味着如果不存在一层的所有数都是 \(1\),那么最终答案也一定是 \(1\),所以得出一条重要结论:如果序列中存在 \(1\),那么最终答案一定为 \(0\)\(1\),这时候 \(0\)\(2\) 其实是等价的,所以转化为 \(mod\) \(2\) 意义下。延伸得到另一条结论:如果不存在 \(1\),那么最终答案一定为 \(0\)\(2\)
  • 上面两种情况没有什么本质区别,第二种也完全可以全部除以 \(2\),转化成 \(0/1\) 序列。而对于 \(0/1\) 序列来说(即在 \(mod\) \(2\)意义下),加减操作和异或操作是等价的,我们只需要进行异或计算就好了。
  • 这时候只需求出最初每个数(指相邻两数之间的差值)的异或次数,而上面说到,这其实是一个杨辉三角,而杨辉三角中的每个数都可以用组合数求出,这个组合数的值的本质含义其实就是三角顶层的那个 \(1\) 到达这个数的路径数,所以将最初的每个数放到杨辉三角上,就可以用组合数求出异或次数,第 \(i\) 个数的次数即为 \(C_{n-1}^{i-1}\)
  • 最后用 \(Lucas\) 定理快速求出组合数值,\(Lucas(n/2,m/2)*C(n\%2,m\%2)\) 其实最后结果就是\(n\&m==m\),不明白可以联系二进制考虑,如果有一位 \(2\) 进制上 \(n\)\(0\),\(m\)\(1\),那么计算结果就是 \(C_0^1\) ,也就是 \(0\)

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
int n, ans, flag;
char s[N], a[N];
bool check(int x, int y)
{
	return (x & y) == y;
}
signed main()
{
	cin >> n;
	n --;
	scanf("%s", s + 1);
	for(int i = 1; i <= n; i ++)
	{
		a[i] = abs(s[i] - s[i + 1]);	
	}
	for(int i = 1; i <= n; i ++)
	{
		if(a[i] == 1)
		{
			flag = 1;
			break;
		}
	}
	if(!flag)
	{
		for(int i = 1; i <= n; i ++)
		{
			a[i] >>= 1;
		}
	}
	for(int i = 1; i <= n; i ++)
	{
		if(check(n - 1, i - 1))
		{
			ans ^= (a[i] & 1);
		}
	}
	if(!flag)
	{
		ans <<= 1;
	}
	cout << ans << endl;
}
posted @ 2026-06-17 17:02  Luowj  阅读(6)  评论(0)    收藏  举报