Bzoj P1411 [ZJOI2009]硬币游戏___规律题

题目大意:

2 n 2n 2n个位置,一开始奇数位置上有 n n n个硬币,依次给出每个硬币是正面还是反面,正面为 1 1 1,反面为 2 2 2。其他位置为 0 0 0,即没有硬币存在。
m m m次操作,每次操作为:
在任意两个硬币之间放上一个硬币,然后将原来的硬币拿走;
所放硬币的正反面由它两边的两个硬币决定,若两个硬币均为正面朝上或反面朝上,则所放硬币为正面朝上,否则为反面朝上。
问操作 m m m次之后 2 n 2n 2n个位置上对应的硬币的放置状态,空的输出 0 0 0,有硬币的话,硬币是正面输出 1 1 1,反面输出 2 2 2
n < = 100000 , m < = 2 60 n<=100000,m<=2^{60} n<=100000,m<=260

分析:

不难发现题目中的每2次操作以后,都是回到初始状态的位置
回到初始状态的位置,即如果你当前是1,3,5,7……的位置,那么下次就是偶数位置序列,再下次就还是现在的奇数位置序列

而对于当前经过2次操作以后的新的硬币摆放状态,
根据在 x o r xor xor运算中,
0 0 0 xor 1 = 1 , 1 1=1,1 1=1,1 x o r xor xor 0 = 1 , 0 0=1,0 0=1,0 x o r xor xor 0 = 0 , 1 0=0,1 0=0,1 x o r xor xor 1 = 0 1=0 1=0
把正面设为 0 0 0,反面设为 1 1 1
不难发现都是对经过2次操作之前的硬币摆放状态中相邻2个数求一个 x o r 和 xor和 xor,然后重新构成的状态
然后我们可以发现对于当前硬币状态 x x x
经过 2 ∗ 2 k 2*2^k 22k次操作以后的硬币摆放状态 y y y
y y y中的第 i i i个元素即为 x x x中的第 i − 2 k i-2^k i2k个数 x o r xor xor上第 i + 2 k i+2^k i+2k个数 (注意这是首尾相连的序列)

证明如下,
k = x k=x k=x的时候
满足当前序列 y y y 2 ∗ 2 x 2*2^{x} 22x次操作之前的序列 X Y XY XY,每个 y i = X Y i − 2 x y_i=XY_{i-2^x} yi=XYi2x x o r xor xor X Y i + 2 x XY_{i+2^x} XYi+2x
那么当 k = x + 1 k=x+1 k=x+1的时候
设当前序列为 z z z
X Y XY XY z z z 2 ∗ 2 x + 1 2*2^{x+1} 22x+1次操作之前的序列
y y y z z z 2 ∗ 2 x 2*2^{x} 22x次操作之前的序列
如果我把 y y y当成初始序列,
那么此时的 k ′ = k − 1 = x + 1 − 1 = x k'=k-1=x+1-1=x k=k1=x+11=x,显然我们已经确定 k ′ = x k'=x k=x是满足的,
所以此时每个 z i = y i − 2 x z_i=y_{i-2^x} zi=yi2x x o r xor xor y i + 2 x y_{i+2^x} yi+2x
因为每个 y i = X Y i − 2 x y_i=XY_{i-2^x} yi=XYi2x x o r xor xor X Y i + 2 x XY_{i+2^x} XYi+2x
所以每个 z i = ( X Y i − 2 x − 2 x z_i=(XY_{i-2^x-2^x} zi=(XYi2x2x x o r xor xor X Y i − 2 x + 2 x ) XY_{i-2^x+2^x}) XYi2x+2x) x o r xor xor ( X Y i + 2 x − 2 x (XY_{i+2^x-2^x} (XYi+2x2x x o r xor xor X Y i + 2 x + 2 x ) XY_{i+2^x+2^x}) XYi+2x+2x)
然后归纳一下可以得到
z i = X Y i − 2 x + 1 z_i=XY_{i-2^{x+1}} zi=XYi2x+1 x o r xor xor X Y i + 2 x + 1 = X Y i − 2 k XY_{i+2^{x+1}}=XY_{i-2^k} XYi+2x+1=XYi2k x o r xor xor X Y i + 2 k XY_{i+2^k} XYi+2k
证毕
那么我们对 m / 2 m/2 m/2进行2进制拆分然后搞一下就可以了,注意一开始如果 m m m是奇数就先把序列翻一遍然后再做。

P S : 不 能 输 出 行 末 空 格 , 否 则 据 说 会 有 点 难 受 PS:不能输出行末空格,否则据说会有点难受 PS

代码:

 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
#define mp(x, y) memcpy(x, y, sizeof(y))
#define N 100005
 
using namespace std;
 
typedef long long ll;
 
int NowNum[N], A[N], n;
ll cdp, m;
 
int main()
{
    scanf("%d %lld", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%d", &A[i]), -- A[i];
    if (m % 2)
    {
        for (int i = 1; i <= n; i++) NowNum[i] = A[i] ^ A[i % n + 1];
        mp(A, NowNum);
    }
    cdp = m / 2;
    for (; cdp;)
    {
        ll x = cdp & (- cdp);
        for (int i = 1; i <= n; i++)
        {
            int l = i - ll(x % n); if (l < 1) l += n;
            int r = i + ll(x % n); if (r > n) r -= n;
            NowNum[i] = A[l] ^ A[r];
        }
        mp(A, NowNum);
        cdp = cdp - x;
    }   
    if (m % 2) { for (int i = 1; i < n; i++) printf("0 %d ", A[i] + 1); printf("0 %d", A[n] + 1); } 
       else { for (int i = 1; i < n; i++) printf("%d 0 ", A[i] + 1); printf("%d 0", A[n] + 1); }
    return 0;
} 


你可能感兴趣的:(暴力/枚举/模拟,C++,规律与思维)