性质发掘+树状数组AGC006E

Posted psychicboom

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了性质发掘+树状数组AGC006E相关的知识,希望对你有一定的参考价值。

好烦啊(O(n^2))跑得比(O(nlogn))快【】
先把一些SB情况判掉

首先可以求出这个矩阵中每一列将被放到哪一列上了

于是先把列号变成目标状态趴OwO

然后你看这个(3 imes 3),每次修改只会交换奇偶性相同两列的位置,可以尝试一下分奇偶讨论,分别求出把奇偶列变成目标状态的次数,树状数组逆序对

于是设(cnt[0/1])表示列号为奇数/偶数的逆序列个数的奇偶性

注意到每次翻转会改变(cnt[中间列列号%2]),就修改一下

把列全部复位后,可以把连续五列中,在不改变其他列的情况下,把任意相隔一列的两列数同时变成逆序

具体过程见下,设列(A,B,C,D,E)分别为列(a,b,c,d,e)的逆序列:

( exttt{a b c d e})

( exttt{C B A d e})

( exttt{C B E D a})

( exttt{e b c D a})

( exttt{e b A d C})

( exttt{a B E d C})

(color{red}{ exttt{a B c D e}})

( exttt{a d C b e})

( exttt{c D A b e})

( exttt{c B a d e})

(color{red}{ exttt{A b C d e}})

最后就判断一下(cnt[0],cnt[1])是不是0就行了

代码:

#include <bits/stdc++.h>
#define N 100005
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
#define NosoL return puts("No"),0
#define SoL return puts("Yes"),0
using namespace std;
int a[4][N],cnt[2],to[N],n,c[N];
void ins(int x){ for(int i=x;i<=n;i+=(i&(-i))) c[i]++; }
int qry(int x){ int res=0;for(int i=x-1;i;i-=(i&(-i)))res+=c[i];return res; }
int main(){
    scanf("%d",&n);
    For(i,1,3) For(j,1,n) scanf("%d",&a[i][j]);
    For(i,1,n){
        if(abs(a[1][i]-a[2][i])!=1 || abs(a[2][i]-a[3][i])!=1) NosoL;
        For(j,1,3) if(a[j][i]%2!=(i+3*j-3)%2) NosoL;
        if(a[1][i]%3==1 && a[1][i]>a[2][i]) NosoL;
        if(a[1][i]%3==0 && a[1][i]<a[2][i]) NosoL;
        to[i]=(a[2][i]+1)/3;
        cnt[i&1]^=(a[1][i]>a[3][i]);    
    }
    For(i,1,n) if(to[i]%2!=i%2) NosoL;
    for(int i=n-(n%2==0);i>=1;i-=2){
        int x=qry(to[i]);
        cnt[0]^=(x&1);
        ins(to[i]);
    }
    For(i,1,n) c[i]=0;
    for(int i=n-(n&1);i>=1;i-=2){
        int x=qry(to[i]);
        cnt[1]^=(x&1);
        ins(to[i]);
    }
    if(!cnt[0] && !cnt[1]) SoL;
    else NosoL;
}

以上是关于性质发掘+树状数组AGC006E的主要内容,如果未能解决你的问题,请参考以下文章

数据结构之树状数组从零认识树状数组

树状数组区间更新区间查询以及gcd的logn性质

算法#3树状数组&二叉索引树

关于树状数组

树状数组 线段树

树状数组的应用及拓展