选举

也许更好的阅读体验
\(\mathcal{Description}\)
problem

data
\(\mathcal{Solution}\)

30分思路

\(f[i]\)表示以\(i\)结尾,划分的区间都合法时,小奇得票数比魔法猪最多多几票
\(sum[i]\)表示支持情况的前缀和
\(j\in[max(i-r,0),max(i-l,0)]\)
\(sum[i]==sum[j]\)\(f[i]=max(f[i],f[j])\)
\(sum[i]\ \ > \ sum[j]\)\(f[i]=max(f[i],f[j]+1)\)
\(sum[i]\ \ < \ sum[j]\)\(f[i]=max(f[i],f[j]-1)\)
复杂度\(O(n*(r-l+1))\)
代码就不贴了

100分思路

考虑优化30分思路,能否用数据结构把\((r-l+1)\)的复杂度优化为\(log\)级别
用一个权值线段树来维护每一个\(sum\)值,即权值线段树中的节点的意义为,若该节点表示区间\([k,k]\)(叶子节点),它维护的值是在当前计算的位置的合法区间\([max(i-r,0),max(i-l,0)]\)内,\(sum\)值为\(k\)的数的\(f\)最大是多少
这样我们只要动态地维护权值线段树就可以了,而每当\(i\)往后移一次,实质上有效区间就是整体往后移了一位,要维护的就只有区间两端的数字,用优先队列维护\(sum\)的最大\(f\)值即可
代码

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年06月22日 星期六 08时06分50秒
*******************************/
#include <cstdio>
#include <fstream>
#include <cstring>
#include <algorithm>
#include <queue>
#define mk make_pair
using namespace std;
const int maxn = 1000006;
const int m = 1000001;
const int inf = 10000007;
const char no [] = "Impossible";
//{{{cin 读入优化
struct IO{
    template<typename T>
    IO & operator>>(T&res){
        res=0;
        bool flag=false;
        char ch;
        while((ch=getchar())>'9'||ch<'0')    flag|=ch=='-';
        while(ch>='0'&&ch<='9') res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
        if (flag)    res=~res+1;
        return *this;
    }
}cin;
//}}}
int n,l,r;
int sum[maxn],f[maxn];
int val[maxn<<3],pos[maxn<<1],lt[maxn<<3],rt[maxn<<3];
priority_queue < pair<int,int> > q[maxn<<1];
//{{{build(k,l,r)
void build (int k,int l,int r)
{
    lt[k]=l,rt[k]=r;
    if (l==r){
        val[k]=-inf,pos[l]=k;
        return ;
    }
    int mid=(l+r)>>1;
    build (k<<1,l,mid);
    build (k<<1|1,mid+1,r);
    val[k]=max(val[k<<1],val[k<<1|1]);
}
//}}}
//{{{insert(u,v)
void insert (int u,int v)
{
    int k=pos[u];
    while (k){
        val[k]=max(val[k],v);
        k>>=1;
    }
}
//}}}
//{{{change(u,v)
void change (int u,int v)
{
    int k=pos[u];
    val[k]=v;
    while (k>>=1)   val[k]=max(val[k<<1],val[k<<1|1]);
}
//}}}
//{{{query(k,l,r)
int query (int k,int l,int r)
{
    if (lt[k]>=l&&rt[k]<=r) return val[k];
    if (lt[k]>r||rt[k]<l)   return -inf;
    int res=-inf;
    res=max(res,query(k<<1,l,r));
    res=max(res,query(k<<1|1,l,r));
    return res;
}
//}}}
int main()
{
    cin>>n>>l>>r;
    for (int i=1;i<=n;++i)  cin>>sum[i],sum[i]+=sum[i-1];
    build(1,1,m<<1);
    for (int i=1;i<=n;++i)  f[i]=-inf;
    f[0]=0,q[0].push(mk(0,0));//二元组(f,k)表示f值和位置
    for (int i=l;i<=n;++i){
        int s=sum[i-l]+m;//防止负数
        insert(s,f[i-l]);
        q[s].push(mk(f[i-l],i-l));
        if (i>r){
            s=sum[i-r-1]+m;
            while (!q[s].empty()&&i-r>q[s].top().second)    q[s].pop();
            if(q[s].empty())    change(s,-inf);
            else    change(s,q[s].top().first);
        }
        s=sum[i]+m;
        f[i]=max(f[i],query(1,1,s-1)+1);
        f[i]=max(f[i],query(1,s,s));
        f[i]=max(f[i],query(1,s+1,m<<1)-1);
    }
    if (f[n]<-n)    printf("%s\n",no);
    else    printf("%d\n",f[n]);
    return 0;
}

转载于:https://www.cnblogs.com/Morning-Glory/p/11079405.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值