UVALive 4726 Average(数形结合)

题意:给出一个01串,选一个长度至少为L的子序列使得子序列数字的平均值最大。

思路:为了这题又看了个论文……是04年国家集训队 周源的《浅谈数形结合思想在信息学竞赛中的应用》,感觉这样不行啊,有时间要好好看看这些论文,不能碰到一道题再去看。其实这个平均值在坐标中画出来就相当于斜率,从而转化成寻找两点之间最大斜率的问题,维护一个下凹的图形序列就行了。感觉我写的有些丑啊,最后调了半天发现初始化错了Orz,不能再sb了


代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct Point
{
    double x,y;
    Point (){};
    Point (double xx,double yy) {x=xx;y=yy;}
};
Point p[maxn];
typedef Point Vector;
double Cross(Vector a,Vector b) {return a.x*b.y-a.y*b.x;}
Vector operator -(Point a,Point b) {return Vector(a.x-b.x,a.y-b.y);}
double calk(Point a,Point b) {  return (b.y-a.y)/(b.x-a.x);}
int dcmp(double x)
{
    if(fabs(x)==0) return 0;
    return x>0?1:-1;
}
char str[maxn];
int n,L,maxl,maxr;
double maxv;
Point sp[maxn];
void solve()
{
    int m=0;
    sp[m++]=p[0];
    int s=0,tmp;
    double k,tmp2;
    bool flag;
    for(int i=L;i<=n;++i)
    {
        flag=false;
        if(s<m&&sp[s].x<=i-L)
        {
            k=calk(sp[s],p[i]);
            while(s+1<m)
            {
                tmp2=calk(sp[s+1],p[i]);
                if(dcmp(k-tmp2)<=0) {s++;k=tmp2;}
                else break;
            }
            tmp=dcmp(k-maxv);
            if(tmp>=0)
            {
                maxv=k;
                if(tmp>0||(tmp==0&&maxr-maxl+1>(int)(p[i].x-sp[s].x+eps)))
                {maxl=sp[s].x+1+eps;maxr=p[i].x+eps;}
            }
        }
        while(m>s+1&&Cross(sp[m-1]-sp[m-2],p[i-L+1]-sp[m-1])<0) m--;
        sp[m++]=p[i-L+1];
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&L);
        scanf("%s",str);
        int sum=0;
        p[0]=Point(0,0);
        for(int i=0;i<n;++i)
        {
            sum+=(str[i]-'0');
            p[i+1]=Point(i+1,sum);
        }
        maxv=0;
        if(L==1)
        {
            if(sum==0) {maxl=maxr=1;}
            else
            {
                for(int i=0;i<n;++i)
                    if(str[i]=='1') {maxl=maxr=i+1;break;}
            }
        }
        else solve();
        printf("%d %d\n",maxl,maxr);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值