Lipshitz
Portal --> broken qwq
Description
大M正在學習函數的光滑性并對Lipschitz常數非常感興趣:當一個定義域為\([l,r]\)的函數\(f\),對于定義域內的任意\(x,y\)都有\(|f(x)-f(y)|<=K*|x-y|\)時,則稱\(K\)為該函數在\([l,r]\)上的Lipschitz常數。 ?
? 然而大M并不滿足于函數,所以他定義:對于一個序列\(v[1..n]\)的Lipschitz常數\(K\),當\(1<=x<y<=n\)且\(x,y\)均為整數時,同樣滿足\(|v[x]-v[y]|<=K*|x-y|\)的\(K\)的最小值
現在給你一個長度為n的序列\(v[1..n]\)并給出\(q\)個詢問,對于每對詢問\([l,r]\),你需要求出\(v[l..r]\)的所有子序列\(v[x..y](l<=x<y<=r)\)的Lipschitz常數之和
? 數據范圍:$n<=100000,q<=100 $
Solution
這題的關鍵在于,要證明對于區間\([l,r]\)來說,\(K\)一定是\(max(\frac{|v[i]-v[i-1]}{|i-(i-1)|})\)
我們可以將\(\frac{|v[x]-v[y]|}{|x-y|}\)看成一個求平均值的過程,再具體一點的話就是如果我們將\(v\)看成一個函數,這個式子其實相當于求一段區間(兩個端點分別是\(x\)和\(y\))中\(|v[i]-v[i-1]|\)的平均值,那么也就是說明最大值顯然應該是在區間長度為\(1\)的時候取得(否則總能通過舍掉較小的部分取得更優的結果)
那所以我們可以直接求得\(K\)的所有可能的取值了(存在\(w\)數組中),接下來還是常用的套路,看每個取值能在哪個區間內提供貢獻
這個其實比較好處理,我們用一個單調棧預處理出每一個\(K\)值的前一個比它大的位置和后一個比它大的位置,前者記為\(pre\),后者記為\(nxt\),那么我們可以直接算出這個由\(|v[i]-v[i-1]|\)產生的\(K\)對答案的貢獻了,它能貢獻的子區間左端點的取值范圍為\(w\)數組中的\([max(l+1,pre+1),i]\),右端點的取值范圍為\(w\)數組中的\([i,min(r,nxt-1)]\),其中\(l,r\)是詢問的區間
? 什么叫做\(w\)數組中的一個區間呢?其實是因為\(w\)數組的定義寫出來的話應該是\(w[i]=|v[i]-v[i-1]|\),也就是說\(w\)中的一個位置其實包含了\(v\)中的兩個位置,這么說好像還是有點繞,但反正就是邊界什么的需要稍微。。自己推一下
? 然后還有一個問題是如果說\(w\)數組中(也就是\(K\)的所有取值中)有重復的怎么處理,那其實比較顯然只要左端點算上重復的,右端點不算上就好了
? (然而。。貌似左端點不算右端點算不太行的樣子(也可能是因為我自己寫挫了),就比如說會出現這種情況:\(w=\{0,2,1,2,1\}\),然后如果左端點不算右端點算的話會把\(K=2\)時的\(\{2,1,2,1\}\)這種情況漏掉)
? 代碼大概長這個樣子
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #define Pr pair<int,int> #define mp make_pair #define ll long long using namespace std; const int N=100010; int a[N],pre[N],nxt[N],loc[N],w[N]; Pr rec[N]; int n,m,top; int Abs(int x){return x<0?-x:x;} bool cmp(int x,int y){return w[x]<w[y];} void prework(){top=0;pre[1]=0; rec[++top]=mp(w[1],1);for (int i=2;i<=n;++i){while(top&&rec[top].first<w[i]) --top;if (top==0) pre[i]=0;else pre[i]=rec[top].second;rec[++top]=mp(w[i],i);}top=0;nxt[n]=n+1; rec[++top]=mp(w[n],n);for (int i=n-1;i>=1;--i){while (top&&rec[top].first<w[i]) --top;if (top==0) nxt[i]=n+1;else nxt[i]=rec[top].second;rec[++top]=mp(w[i],i);} } void solve(int l,int r){int L,R;ll ans=0;for (int i=l+1;i<=r;++i){L=max(l+1,w[pre[i]]==w[i]?pre[i]:pre[i]+1),R=min(nxt[i]-1,r);ans+=1LL*w[i]*((R-i+1)*(i-L+1));//printf("%d %d\n",w[i],(R-i+1)*(i-L+1));}printf("%lld\n",ans); }int main(){ #ifndef ONLINE_JUDGEfreopen("a.in","r",stdin); #endifint l,r;scanf("%d%d",&n,&m);for (int i=1;i<=n;++i) scanf("%d",a+i);w[1]=0;for (int i=2;i<=n;++i) w[i]=Abs(a[i]-a[i-1]);prework();for (int i=1;i<=m;++i){scanf("%d%d",&l,&r); solve(l,r);} } /* input1 10 4 1 5 2 9 1 3 4 2 1 7 2 4 3 8 7 10 1 9output1 17 82 23 210input2 7 6 5 7 7 4 6 6 2 1 2 2 3 2 6 1 7 4 7 3 5output2 2 0 22 59 16 8 */轉載于:https://www.cnblogs.com/yoyoball/p/9383205.html
總結
- 上一篇: eclipse 中 Android sd
- 下一篇: 加快上架方法