专门为这题写个题解。
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。
②答案为000或111或222。
证明方法与①同理。
③如果经历了一次变换后序列中存在111,则答案不能为222。
假设第iii个位置为111,在第iii个位置左边的数为000或111或222。经历了一次变换后,位置为i−1i-1i−1的这个数只能是000或111,因为∣2−1∣=∣0−1∣=1,∣1−1∣=0|2-1|=|0-1|=1, |1-1|=0∣2−1∣=∣0−1∣=1,∣1−1∣=0。扩展到整个序列的情况,222会因为111的存在慢慢消失。
于是,我们先对这个序列做一次变换,并开始大力分讨。
假设当前序列中只有000和111。可以发现,最终答案只能是000或111。
由于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=∣a−b∣,所以,我们每次的变换相当于"第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,a3……an,那么答案就是(∑i=1nCn−1i−1ai) mod 2(\sum_{i=1}^n C_{n-1}^{i-1} a_i)\ mod\ 2(i=1∑nCn−1i−1ai) mod 2
假设k!k!k!中质因数222的个数为numknum_knumk,那么CxyC_x^yCxy的质因数222的个数就是numx−numy−numx−ynum_x-num_y-num_{x-y}numx−numy−numx−y。如果这个值为正,那么就是偶数;否则就是奇数。于是,010101序列的情况就处理完了。
注意到,这个序列中可能还含有222。我们继续大力分讨。
假设这个序列只有000和222,显然最终答案只能是000或222,不能是111。但是,我们仍然可以将这个序列转化为010101序列的情况。即,我们将这个020202序列中每个数都除以222,变成010101序列;最终的答案为010101序列的答案的两倍。
最后一种情况: 这个序列存在0,1,20,1,20,1,2。
可以发现,根据性质③中的"如果经历了一次变换,序列中存在111,则答案不能为222",得到答案只能为000或111。于是,我们可以将222变成000,此时转化为010101序列就直接用上述方法去算,最终答案显然不变。
于是,这道神仙题就做完了。时间复杂度O(n)O(n)O(n)。
有必要总结一下。这题中,我们可以通过打表或思考来发现三个性质,然后将模型简化为010101序列,再扩展为其他情况,最终通过找规律与组合数、数论巧妙地解决了本题。
作为一道AGCAGCAGC的BBB题,这是比较难的,但是毫无疑问,本题考查得十分综合,是一道不可多得的好题。
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;
}
本文针对一个特定序列进行变换操作,探讨其最终值的规律。通过对序列的性质分析,结合杨辉三角形及组合数学原理,得出高效求解方法。

758

被折叠的 条评论
为什么被折叠?



