codevs 1283 等差子序列
http://codevs.cn/problem/1283/
題目描述?Description給一個 1 到 N 的排列{Ai},詢問是否存在 1<=p1<p2<p3<p4<p5<…<pLen<=N(Len>=3),使得 Ap1,Ap2,Ap3,…ApLen?是一個等差序列。
輸入描述?Input Description輸入的第一行包含一個整數 T,表示組數。
?下接 T 組數據,每組第一行一個整數 N,每組第二行為一個 1 到 N 的排列, 數字兩兩之間用空格隔開。
輸出描述?Output Description對于每組數據,如果存在一個等差子序列,則輸出一行“Y”,否則輸出一 行“N”。
樣例輸入?Sample Input2
3
1 3 2
3
3 2 1
樣例輸出?Sample OutputN
Y
數據范圍及提示?Data Size & Hint對于5%的數據,N<=100,對于30%的數據,N<=1000,對于100%的數據,N<=10000,T<=7
?
線段樹+hash
首先要注意的是這個排列是1到n的排列
然后當然是找3個數形成等差子序列
暴力:枚舉中間的數,枚舉左邊的數,枚舉右邊的數,看是否滿足 2*mid=l+r
O(n3)
繼續想,因為保證排列是1到n
所以對于一個數x,若以x為mid能形成等差子序列,那么另外兩個數一定在x兩側
即從左往右枚舉,當枚舉到mid時,能早就枚舉到了l,不能枚舉到r
可以用0,1表示這個數是否被枚舉到
舉個例子:
3 6 1 2 4 5
當枚舉到第5個數4時,0 1序列為
1 1 1 1 0 1
4的左邊分別是1和0,說明枚舉到4時,3已經被枚舉到了,5還沒有被枚舉
但這樣仍然要枚舉,沒有減少時間復雜度
如何去掉枚舉的過程?
繼續想,發現我們要比較的是mid左右的兩個對稱區間
舉個例子:
1 8 3 6 5 7 4 2
當枚舉到3時,0 1序列為:
1 0 1 0 0 0 0 1
我們實際需要的是判斷2和4的01序列是否相等,1和5的01序列是否相等
因為是對稱的
可以轉化為判斷區間[1,2]和區間[5,4](注意這里是[5,4],不是[4,5])是否相等
線段樹維護區間正序哈希值和倒序哈希值,即可log判斷
總復雜度:O(nlogn)
#include<cstdio> #include<cstring> #include<algorithm> #define N 10001 #define LL unsigned long long using namespace std; int T,n,x,len; bool ok; LL bit[N],hash[N*4],anti_hash[N*4],r1,r2; struct TREE {public:void up(int k,int l,int r){hash[k]=hash[k<<1]*bit[r-(l+r>>1)]+hash[k<<1|1];anti_hash[k]=anti_hash[k<<1|1]*bit[(l+r>>1)-l+1]+anti_hash[k<<1];}void change(int k,int l,int r,int pos){if(l==r) {anti_hash[k]=hash[k]=1;return;}int mid=l+r>>1;if(pos<=mid) change(k<<1,l,mid,pos);else change(k<<1|1,mid+1,r,pos);up(k,l,r);}LL query(int k,int l,int r,int opl,int opr,int w){if(l>=opl&&r<=opr) return w==1 ? hash[k]:anti_hash[k];int mid=l+r>>1;if(opr<=mid) return query(k<<1,l,mid,opl,opr,w);else if(opl>mid) return query(k<<1|1,mid+1,r,opl,opr,w);else if(w==1) return query(k<<1,l,mid,opl,mid,w)*bit[opr-mid]+query(k<<1|1,mid+1,r,mid+1,opr,w);else return query(k<<1|1,mid+1,r,mid+1,opr,w)*bit[mid-opl+1]+query(k<<1,l,mid,opl,mid,w);}void solve(int i){len=min(i-1,n-i);r1=query(1,1,n,i-len,i-1,1);r2=query(1,1,n,i+1,i+len,2);if(r1!=r2) ok=true;} }tree; int main() {bit[1]=233; for(int i=2;i<N;i++) bit[i]=bit[i-1]*233;scanf("%d",&T);while(T--){memset(hash,0,sizeof(hash));memset(anti_hash,0,sizeof(anti_hash));scanf("%d",&n);ok=false;for(int i=1;i<=n;i++){scanf("%d",&x);if(!ok){tree.change(1,1,n,x);if(x!=1&&x!=n) tree.solve(x);}}if(ok) puts("Y");else puts("N");} }?
轉載于:https://www.cnblogs.com/TheRoadToTheGold/p/6813049.html
總結
以上是生活随笔為你收集整理的codevs 1283 等差子序列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS事件的响应和传递机制
- 下一篇: Android媒体解码MediaCode