1. 程式人生 > >【[國家集訓隊]等差子序列】

【[國家集訓隊]等差子序列】

%d 開始 return esp 相等 這一 都在 bool 如何

bitset 解法

一、思路很簡單:

首先,找>=3個和找3個沒區別。題目大霧。

一個權值bool數組,當這一位是a時,把a這一位設成1, 查詢以a位置為中心的,以n或者1為邊界的對稱區域是否是回文的。

如果是,說明,可以所有和a等差的項都在前面出現了。

反之不是,就說明有一組的一項在前面出現了,而另一項在前面沒有出現過。因為序列是一個1~n的排列,所以另一項肯定在後面出現了。

----> 帶修判斷區間回文問題 轉化成功!

二、正解:

這個題正解是線段樹維護hash值(可以想象得到)。

但是太難寫了(蒟蒻一個)

所以就寫了bitset。

(卡n=10000啊,再大了就不行了)

開兩個bitset,

一個從前面看叫bf(bitset_front)

一個從後面看叫bb(bitset_back)

每次遇到一個數a,

就bf.set(a),bb.set(n-a+1)

比較的時候,取出兩半的回文位置比較是否相等就好啦!

取的時候,

分w>n/2,w<=n/2 討論,因為回文半徑和bf,bb負責的部分是不同的。

由於要去掉其他幹擾位置,就又開了一個bas數組。每次O(n)設置1。需要的時候,左移右移按位與去掉幹擾位置。

還有註意,bitset是從0開始的。

所以為了去掉可能的0幹擾問題,就都每次set(0)就好啦。

復雜度:O(n^2/32 = 3125000 )

至於如何準確取出,

大家看代碼,自行畫圖理解吧。

(真正提升總是要手動理解的嘛)

代碼:

#include<bits/stdc++.h>
using namespace std;
const int N=10000+10;
int n,t,a;
bitset<N>bf,bb,bas,c,d;
void clr(){
    bf.reset();bb.reset();bas.reset();
}
bool che(int w){
    if(w>n/2){
        c=bf>>(w-1);c.set(0);
        d=(bb>>(n-w))&(bas>>(w-1
));d.set(0); if(d!=c) return true; return false; } else{ c=(bf&(bas>>(n-w)));c.set(0); d=((bb>>(n-2*w+1))&(bas>>(n-w)));d.set(0); if(c!=d) return true; return false; } } int main() { scanf("%d",&t); while(t--){ clr(); scanf("%d",&n); for(int i=1;i<=n;i++) bas.set(i); bool fl=false; for(int i=1;i<=n;i++) { scanf("%d",&a);bf.set(a),bb.set(n-a+1); if(che(a)) fl=true; } if(fl) printf("Y\n"); else printf("N\n"); } return 0; }

【[國家集訓隊]等差子序列】