娃娃机 解题报告

娃娃机

如果每个点坐标都已经确定,可以形式化的得到一个直接计算答案的式子。

\[ans=10^6-y_0+(\sum_{i=2}^n\max_y[\min(x_i,x_{i-1}),\max(x_i,x_{i-1})]-y_i-y_{i+1})+10^6-y_n \]

带中括号的表示区间最大值

化简一下可以得到

\[2(10^6-\sum y_i+(\sum_{i=2}^n\max_y[\min(x_i,x_{i-1}),\max(x_i,x_{i-1})])) \]

考虑通过调制最大化这个式子

\[\sum y_i-(\sum_{i=2}^n\max_y[\min(x_i,x_{i-1}),\max(x_i,x_{i-1})]) \]

可以发现,对于每一个最大值,是可以独立的去讨论的,也就是说,考虑枚举最大值,那么可以得到跨过这个最大值的一些区间,对每个最大值可以独立统计。

于是问题转换成了可以对某个最大值的某些点+1,最大化 +1的个数-区间内存在+1的数的区间的个数。

再补集转换一下统计 +1的个数+区间内不存在+1的数的区间的个数

这样可以dp了,设\(dp_i\)表示从小到大对点排序第\(i\)个点钦定+1的最大值

\[dp_i=\max_{j<i}(dp_j+calc_{j+1,i-1}+1) \]

中间的\(calc_{l,r}\)表示区间\([l,r]\)完全覆盖的区间个数

这个转移可以拿线段树优化

总复杂度\(O(n\log n)\)


Code:

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#define ll long long
using std::min;
using std::max;
const int N=1e6+10;
const int M=1e6;
template <class T>
void read(T &x)
{
    x=0;char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
int st[21][N],Log[N];
int qry(int l,int r)
{
    if(l>r) std::swap(l,r);
    int d=Log[r+1-l];
    return max(st[d][l],st[d][r-(1<<d)+1]);
}
int n,dx[N],dy[N];
ll ans;
std::vector<int> pot[N],seg[N];
struct node
{
    int l,r;
    node(){}
    node(int L,int R){l=L,r=R;}
    bool friend operator <(node a,node b){return a.r<b.r;}
}bee[N];
int yuy[N];
int mx[N<<2],tag[N<<2];
#define ls id<<1
#define rs id<<1|1
void pushdown(int id)
{
    if(tag[id])
    {
        tag[ls]+=tag[id];
        mx[ls]+=tag[id];
        tag[rs]+=tag[id];
        mx[rs]+=tag[id];
        tag[id]=0;
    }
}
void ins(int id,int l,int r,int p,int d)
{
    if(l==r){mx[id]=d;return;}
    pushdown(id);
    int mid=l+r>>1;
    if(p<=mid) ins(ls,l,mid,p,d);
    else ins(rs,mid+1,r,p,d);
    mx[id]=max(mx[ls],mx[rs]);
}
void modi(int id,int l,int r,int p)
{
    if(!p) return;
    if(r==p)
    {
        ++tag[id],++mx[id];
        return;
    }
    pushdown(id);
    int mid=l+r>>1;
    if(p<=mid) modi(ls,l,mid,p);
    else modi(ls,l,mid,mid),modi(rs,mid+1,r,p);
    mx[id]=max(mx[ls],mx[rs]);
}
void build(int id,int l,int r)
{
    mx[id]=tag[id]=0;
    if(l==r) return;
    int mid=l+r>>1;
    build(ls,l,mid),build(rs,mid+1,r);
}
void work(int x)
{
    if(seg[x].empty())
    {
        ans=ans-pot[x].size();
        return;
    }
    int n=1,m=0;
    for(int i=0;i<pot[x].size();i++) yuy[++n]=dx[pot[x][i]];
    std::sort(yuy+1,yuy+1+n);
    for(int i=0;i<seg[x].size();i++)
    {
        int p=seg[x][i],l=dx[p-1],r=dx[p];
        if(l>r) std::swap(l,r);
        l=std::lower_bound(yuy+1,yuy+1+n,l)-yuy;
        r=std::upper_bound(yuy+1,yuy+1+n,r)-yuy-1;
        bee[++m]=node(l,r);
    }
    std::sort(bee+1,bee+1+m);
    build(1,1,n);
    int j=1;
    for(int i=1;i<n;i++)
    {
        while(j<=m&&bee[j].r==i) modi(1,1,n,bee[j++].l-1);
        ins(1,1,n,i+1,mx[1]+1);
    }
    while(j<=m&&bee[j].r==n) modi(1,1,n,bee[j++].l-1);
    ans-=1ll*(mx[1]-m);
}
int main()
{
    read(n);
    for(int i=1;i<=n;i++) read(dx[i]),read(dy[i]),++dx[i],pot[dy[i]].push_back(i);
    for(int i=1;i<=n;i++) st[0][dx[i]]=dy[i];
    for(int i=2;i<=M;i++) Log[i]=Log[i>>1]+1;
    for(int j=1;j<=20;j++)
        for(int i=1;i<=M+1-(1<<j)+1;i++)
            st[j][i]=max(st[j-1][i],st[j-1][i+(1<<j-1)]);
    ans=M-dy[1];
    for(int i=2;i<=n;i++)
    {
        int mx=qry(dx[i-1],dx[i]);
        ans=ans+mx-dy[i];
        seg[mx].push_back(i);
    }
    for(int i=0;i<=M;i++)
        work(i);
    printf("%lld\n",2ll*ans);
    return 0;
}

2019.3.23

posted @ 2019-03-23 20:50  露迭月  阅读(214)  评论(0编辑  收藏  举报