1. 程式人生 > >【HDU 6319】 暑期多校day3 Ascending Rating (雙端單調佇列)

【HDU 6319】 暑期多校day3 Ascending Rating (雙端單調佇列)

題目大意

給定一個序列 a[1..n],對於每個長度為 m 的連續子區間,
求出區間 a 的最大值以及從左往右掃描該區間時 a 的最大值的變化次數。(1mn107)

解題思路

今天上午的時候剛幫高中教練驗了一道幾乎一樣的題,只不過是雙權值,而且資料範圍茲磁時間複雜度 O(nlogn) 的解法。然鵝下午的多校做到這道題了,感覺上午的做法並沒有什麼卵用,甚至可以讓學弟把資料擴大一些。(毒瘤

從後往前掃,維護一個嚴格遞減的雙端單調佇列,每掃到一個滑窗時佇列裡的隊首元素就是當前滑窗內的最大值,佇列的元素個數就是最大值被改變的次數。

最大值部分的正確性顯然,至於最大值被更新的次數,可知佇列中的任意兩個相鄰元素在

a[] 陣列中的所在的位置之間的 ai 值必定不大於這兩個元素。那麼在這個滑窗裡,這兩個元素必定是更新最大值是被更新上去過的元素。

程式碼

#include <bits/stdc++.h>
using namespace std;

inline int read() {
    register int val=0, sign=1; char ch;
    while(~(ch=getchar()) && (ch<'0' || ch>'9') && ch!='-'); ch=='-'?sign=-1:val=ch-'0'
; while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+ch-'0'; return val*sign; } #define mp make_pair #define x first #define y second const int maxn=int(1e7)+11; typedef pair<int,int> pii; int n,m,k,q,p,r,moder; int a[maxn]; deque<pii>
que; long long ans1, ans2; void ins(int val,int id) { if(que.size() && que.front().y>=id+m) que.pop_front(); while(que.size() && que.back().x<=val) que.pop_back(); que.push_back(mp(val,id)); return; } void update(int id) { int maxval=que.front().x, cnt=que.size(); ans1+=maxval^id; ans2+=cnt^id; return; } void init() { while(que.size()) que.pop_back(); ans1=ans2=0; return; } void work() { n=read(), m=read(), k=read(), p=read(), q=read(), r=read(), moder=read(); init(); register int i; for(i=1;i<=k;++i) a[i]=read(); for(i=k+1;i<=n;++i) a[i]=(1ll*p*a[i-1]+1ll*q*i+r)%moder; for(i=n;i>=1;--i) { ins(a[i],i); if(i<=n-m+1) update(i); } printf("%I64d %I64d\n",ans1,ans2); return; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); #endif int cas=read(); while(cas--) work(); return 0; }