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;
}

浙公网安备 33010602011771号