CF452F Permutations/Luogu2757 等差子序列 树状数组、Hash
傳送門——Luogu 傳送門——Codeforces
如果存在長度\(>3\)的等差子序列,那么一定存在長度\(=3\)的等差子序列,所以我們只需要找長度為\(3\)的等差子序列。可以枚舉等差子序列的第二個元素\(b\),那么存在長度為\(3\)的等差子序列等價于:可以在\(b\)左邊找到一個元素\(a\),在\(b\)右邊找到一個元素\(c\),滿足\(b - a = c - b\)。
對于找到\(ac\)兩個元素,一個比較直觀的想法是:對\(b\)左邊和右邊的所有元素各建一個bitset\(B1,B2\),對于某一個元素\(d \neq b\),如果\(d\)在\(b\)左邊,那么\(B1[d]=1\),否則\(B2[d]=1\)。
不存在等差子序列意味著如果\(d\)在左邊,則\(2 \times b - d\)一定不能在右邊,反之同理。這等價于對于\([l,b-1](l \geq 1),[b + 1 , r](r \leq N)\),滿足\(b - l = r - b\)時,有
\[B1[l,b-1] \lor rev(B2[b+1 , r]) = 2^{b - l} - 1\]
上面兩個條件等價的原因是:若結果的第\(d\)位為\(0\),則\(B1[l,b-1]\)和\(rev(B2[b+1 , r])\)的第\(d\)位要么同時為\(0\),要么同時為\(1\)。若同時為\(0\)意味著\(b-d\)不在左邊且\(b+d\)不在右邊,同時為\(1\)意味著\(b-d\)在左邊且\(b+d\)在右邊,都存在等差子序列。如果其中有一個為\(0\),有一個為\(1\),\(b-d\)和\(b+d\)就會在同一邊。
這樣就可以從右往左枚舉\(b\)的位置,動態維護\(B1,B2\)并查詢。但是當數據范圍到\(3 \times 10^5\)的時候bitset會TLE,這時可以使用Hash+樹狀數組維護與上面bitset意義相同的01串。復雜度變為\(O(nlogn)\)。
雖然CF是神機,但仍然需要注意常數。
//Luogu2757 #include<iostream> #include<cstdio> #include<vector> #include<cstdlib> #include<algorithm> #include<cstring> //This code is written by Itst using namespace std;inline int read(){int a = 0;char c = getchar();while(!isdigit(c)) c = getchar();while(isdigit(c)){a = a * 10 + c - 48;c = getchar();}return a; }#define st first #define nd second struct PII{int first , second;PII(int x = 0 , int y = 0):first(x) , second(y){}bool operator ==(PII a){return a.st == first && a.nd == second;}bool operator !=(PII a){return !(*this == a);} }; const int MAXN = 1e4 + 7 , Base = 131 , MOD1 = 1e9 + 7 , MOD2 = 1e9 + 9; PII powBs[MAXN] , sum[MAXN] , powInv[MAXN]; int arr[MAXN] , N , T; bool f;PII operator *(PII a , PII b){return PII(1ll * a.st * b.st % MOD1 , 1ll * a.nd * b.nd % MOD2); }PII operator +(PII a , PII b){PII t(a.st + b.st , a.nd + b.nd);if(t.st >= MOD1) t.st -= MOD1;if(t.nd >= MOD2) t.nd -= MOD2;return t; }PII operator -(PII a , PII b){return a + PII(MOD1 - b.st , MOD2 - b.nd);}struct BIT{ #define lowbit(x) (x & -x)PII arr[MAXN];BIT(){memset(arr , 0 , sizeof(PII) * (N + 1));}void add(int pos , PII cur){while(pos <= N){arr[pos] = arr[pos] + cur;pos += lowbit(pos);}}PII get(int pos){PII sum = PII(0 , 0);while(pos){sum = sum + arr[pos];pos -= lowbit(pos);}return sum;} }Tree1 , Tree2;inline int poww(long long a , int b , int MOD){int times = 1;while(b){if(b & 1) times = times * a % MOD;a = a * a % MOD;b >>= 1;}return times; }void init(){powBs[0] = sum[0] = powInv[0] = PII(1 , 1);for(int i = 1 ; i <= 10000 ; ++i){powBs[i] = powBs[i - 1] * PII(Base , Base);sum[i] = sum[i - 1] + powBs[i];}powInv[1] = PII(poww(Base , MOD1 - 2 , MOD1) , poww(Base , MOD2 - 2 , MOD2));for(int i = 2 ; i <= 10000 ; ++i)powInv[i] = powInv[i - 1] * powInv[1]; }void work(){for(int i = 1 ; i <= N ; ++i)Tree1.add(arr[i] , powBs[arr[i]]);for(int i = N ; i ; --i){Tree1.add(arr[i] , PII(0 , 0) - powBs[arr[i]]);if(arr[i] != 1 && arr[i] != N){int l1 = 1 , r1 = arr[i] - 1 , l2 = arr[i] + 1 , r2 = N;if(r2 - l2 < r1 - l1) l1 = r1 - (r2 - l2);else r2 = l2 + (r1 - l1);PII t = (Tree1.get(r1) - Tree1.get(l1 - 1)) * powInv[l1] + (Tree2.get(N + 1 - l2) - Tree2.get(N - r2)) * powInv[N - r2 + 1];if(t != sum[r1 - l1]){f = 1;return;}}Tree2.add(N - arr[i] + 1 , powBs[N - arr[i] + 1]);} }signed main(){ #ifndef ONLINE_JUDGEfreopen("in","r",stdin);//freopen("out","w",stdout); #endifinit();for(int T = read() ; T ; --T){N = read();f = 0;for(int i = 1 ; i <= N ; ++i)arr[i] = read();Tree1 = BIT(); Tree2 = BIT();work();puts(f ? "Y" : "N");}return 0; }轉載于:https://www.cnblogs.com/Itst/p/10629524.html
總結
以上是生活随笔為你收集整理的CF452F Permutations/Luogu2757 等差子序列 树状数组、Hash的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jenkins和Jmeter的集成
- 下一篇: 实验总结二