uva1451 Average 单调栈求凸包

#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;i++)
#define MS0(a) memset(a,0,sizeof(a))

using namespace std;

typedef long long ll;
const int maxn=1000100;
const int INF=1<<29;

int n,L;
ll a[maxn],s[maxn];
struct Point
{
    ll x,y;
    friend Point operator-(Point A,Point B)
    {
        return {A.x-B.x,A.y-B.y};
    }
    friend ll operator*(Point A,Point B)
    {
        return 1LL*A.x*B.y-1LL*A.y*B.x;
    }
    void debug()
    {
        printf("%lld %lld
",x,y);
    }
};Point p[maxn],stk[maxn];int tp;
Point ans,Max;

int main()
{
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    int T;cin>>T;
    while(T--){
        scanf("%d%d",&n,&L);
        REP(i,1,n) scanf("%1d",&a[i]);
        s[0]=0;REP(i,1,n) s[i]=s[i-1]+a[i];
        REP(i,0,n) p[i]={i,s[i]};
        //REP(i,0,n) p[i].debug();cout<<endl;
        tp=0;
        Max=(Point){1,0};ans=(Point){1,L};
        int pre=1;
        REP(i,L,n){
            while(tp>1&&(stk[tp]-stk[tp-1])*(p[i-L]-stk[tp])<0) tp--;
            //cout<<"tp:";stk[tp].debug();
            //cout<<"p[i-L]:";p[i-L].debug();
            //cout<<(stk[tp]-stk[tp-1])*(p[i-L]-stk[tp])<<endl;
            stk[++tp]=p[i-L];
            if(pre>tp) pre=tp;
            int j=pre;
            Point tmp={1,0},res={1,L};
            while(j<=tp){
                if(tmp*(p[i]-stk[j])>0){
                    tmp=p[i]-stk[j];
                    res=(Point){stk[j].x+1,i};
                    pre=j;
                }
                else if(tmp*(p[i]-stk[j])==0){
                    if(i-(stk[j].x+1)<res.y-res.x){
                        tmp=p[i]-stk[j];
                        res=(Point){stk[j].x+1,i};
                        pre=j;
                    }
                    else if(i-(stk[j].x+1)==res.y-res.x){
                        if(stk[j].x+1<res.x){
                            tmp=p[i]-stk[j];
                            res=(Point){stk[j].x+1,i};
                            pre=j;
                        }
                    }
                }
                else break;
                j++;
            }
            if(Max*tmp>0) Max=tmp,ans=res;
            //puts("stk:");REP(i,1,tp) stk[i].debug();
        }
        printf("%lld %lld
",ans.x,ans.y);
        //cout<<Max.y<<"/"<<Max.x<<endl;
    }
    return 0;
}

/**
直接搞段平均值是很难的,但是平均值可以转化为段和,再转化为前缀和,
再由构造(i,s[i])的图像通过斜率观察平均值,然后用单调栈维护单调性求个上(下)凸包就可以了。
本来以为算法出错了,对拍了半天原来是题目看错了。。。fuck。。
*/
View Code
没有AC不了的题,只有不努力的ACMER!
原文地址:https://www.cnblogs.com/--560/p/5041264.html