【学习笔记】2021.10.16 - zhengru IOI 七连测 Day7
T1 字符串
Subtask 1 60pts
思路
- 直接用 string 暴力模拟即可
代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
using namespace std;
string A,B,AU,BU;
int n,m,T,x;
long long maxsize;
inline bool doit(int xxx){
if(maxsize>=xxx) return true;
AU=A+B;
BU=B+A;
A=AU;
B=BU;
maxsize=A.length();
if(maxsize>=xxx) return true;
return false;
}
int main(){
scanf("%d%d%d",&n,&m,&T);
cin>>A>>B;
while(T--){
scanf("%d",&x);
while(!doit(x));
printf("%c\n",A[x-1]);
}
return 0;
}
正解
思路
-
因为 \(A_0\) 和 \(B_0\) 的长度不定,所以选择 \(A_1\) 和 \(B_1\) 作为根元素来进行操作,因为它们的长度都是 n+m 。
-
所以,我们先考虑求出每一个 x 在 \(A_{935}\) 中属于第几个元素,显然是 \(\left\lfloor \frac{x-1}{n+m} \right\rfloor + 1\) (就是上取整呀)。
-
但是,怎么确定这个元素是 \(A_1\) 还是 \(B_1\) 呢?
-
从 0 开始编号,此时上文的编号变成\(\left\lfloor \frac{x-1}{n+m} \right\rfloor\),记为 \(S\) ,不难证明如果 \((S)_2\) 中有奇数个 1 则为 \(B_1\) ,反之为 \(A_1\) 。
-
这个很好证明,因为每次操作都是把当前序列取反一下再放在后面,也就是每次都会 \(\times 2\) ,所以每隔 \(2\) 的若干次方就会发生一次翻转,也就是说二进制表示下的 \(x\) 每多一个 1 就会发生翻转,所以这个元素属于什么只和二进制表示下的这个数中有多少个 1 的奇偶性有关。
-
当然了,奇数偶数对应什么取决于你从哪里开始标号,从 0 开始自然就是这样了。
代码
还没写……