題意:給出乙個長度為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。
voidupdate
(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 不容易系列之一 題目描述 大家常常感慨,要做好一件事情真的不容易,確實,失敗比成功容易多了!做好 一件 事情尚且不易,若想永遠成功而總從不失敗,那更是難上加難了,就像花錢總是比掙錢容易的道理一樣。話雖這樣說,我還是要告訴大家,要想失敗到一定程度也是不容易的。比如,我高中的時...