uva 1451 Average 斜率優化

2021-07-16 00:19:42 字數 3082 閱讀 5959

題意:給出乙個長度為n的字串(01串),要求找到長度至少為k的連續子串的最大平均值。n<=1e5。

解:對於任意一段[le,ri]的平均值,都有如下求法:(sum[ri]-sum[le-1])/(ri-le+1)

將(le-1,sum[le-1])看成是乙個點,是點le在圖上的點。

對於每個點i,在圖上對應的點都是(i-1,sum[i-1])

用斜率優化+單調佇列  必須保證佇列裡面的元素是凹的,如果是上凸可能會是錯的(取最優元素時會出錯,因為不滿足凹性)。

因為長度至少是l,所以對於每乙個位置x>=l,用單調佇列維護[  1,x-l+1 ],內的點,使其形狀為下凸(凹)。

優化原理:如果,假若佇列裡有3個元素,對應橫座標是  x1-1

那麼 x2-1這個點可以去掉,原因如下:

雖然實際計算時,公式是 sum[x]-sum[x2-1]/(x-x2)並不是 (sum[x-1]-sum[x2-1])/(x-x2+1)

但因為x>x2,仍然可以看成是某個點xp-1,所以完全可以理解為斜率

如果所示的豎直線:如果某點x縱座標》=b,那麼k(x3-1,x)>=k(x2-1,x)

,否則(縱座標=k(x2-1,x),所以x2-1這個點可以去掉,

所以佇列中的點應該是下凸的。

不去掉不但速度變慢,而且因為沒***下凸會出錯。

判斷上凸:

實測兩種方法都能ac

1.kab>=kac

2.kab>=kbc

#include#include#include#include#include#include#includeusing namespace std;

#define all(x) (x).begin(), (x).end()

#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)

#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)

#define mes(a,x,s) memset(a,x,(s)*sizeof a[0])

#define mem(a,x) memset(a,x,sizeof a)

typedef long long ll;

typedef pairpii;

const int inf =0x3f3f3f3f;

const int maxn= 100000 ;

const double eps=1e-10;

int n,l;

char s[maxn+10];

ll sum[maxn+10];int rear,front,q[maxn+10];

int ansl,ansr;

double ans;

void update(int le,int ri)

else if( (ansr-ansl+1)*(sum[ri]-sum[le-1]) ==(ri-le+1)*(sum[ansr]-sum[ansl-1]) )

printf("%d %d\n",ansl,ansr);

}return 0;}/*

123213

12 5

000101101000

4 20101

*/

#include#include#include#include#include#include#includeusing namespace std;

#define all(x) (x).begin(), (x).end()

#define for0(a, n) for (int (a) = 0; (a) < (n); (a)++)

#define for1(a, n) for (int (a) = 1; (a) <= (n); (a)++)

#define mes(a,x,s) memset(a,x,(s)*sizeof a[0])

#define mem(a,x) memset(a,x,sizeof a)

typedef long long ll;

typedef pairpii;

const int inf =0x3f3f3f3f;

const int maxn= 100000 ;

const double eps=1e-10;

int n,l;

char s[maxn+10];

ll sum[maxn+10];int rear,front,q[maxn+10];

int ansl,ansr;

double ans;

void update(int le,int ri)

else if( (ansr-ansl+1)*(sum[ri]-sum[le-1]) ==(ri-le+1)*(sum[ansr]-sum[ansl-1]) )

printf("%d %d\n",ansl,ansr);

}return 0;

}

對於判斷上凸,這兩種做法都能ac。

void

update

(int le,

int ri)

elseif(

(ansr-ansl+1

)*(sum[ri]-sum[le-1

])==(ri-le+1

)*(sum[ansr]-sum[ansl-1]))

}}

cross

(q[rear-2

],q[rear-1

],q[rear-1

],i-l+1

)>=

0

cross

(q[rear-2

],i-l+1

,q[rear-1

],i-l+1

)>=

0

uva 1451 Average 數形結合

數形結合那篇 的例題,維護乙個下凸佇列,一開始為了省事,用了棧,但是原理上有問題,因為有可能正好起點為上凸點的情況,wa了好多次 author jxy lang c c university china,xidian university if you need to reprint,please ...

Uva 1451 Average(數形結合)

題目鏈結 紫書243頁例題,採用數形結合的方法,用deque來維護乙個單調結點的佇列,即不包含上凸點的序列,每次都更新結果,記錄最優解。includeusing namespace std const int maxn 100050 int n,l char st maxn int s maxn d...

排錯公式 jobdu 1451

jobdu 題目1451 不容易系列之一 題目描述 大家常常感慨,要做好一件事情真的不容易,確實,失敗比成功容易多了!做好 一件 事情尚且不易,若想永遠成功而總從不失敗,那更是難上加難了,就像花錢總是比掙錢容易的道理一樣。話雖這樣說,我還是要告訴大家,要想失敗到一定程度也是不容易的。比如,我高中的時...