码迷,mamicode.com
首页 > 其他好文 > 详细

夏令营

时间:2017-08-11 10:36:51      阅读:193      评论:0      收藏:0      [点我收藏+]

标签:nbsp   ret   bsp   names   return   lin   nan   解释   线段   

夏令营

(camp.pas/c/cpp) 128MB 2s

Nano想靠刷题来增长实力,于是她从题库中找到了n道题打算在夏令营的时候全部刷掉。她计划按题号顺序一道一道刷。n道题中有DP,有贪心,有图论,也有模拟……各种各样的类型都有。夏令营有k天,她想合理安排每天的刷题量,使得每天能刷到尽量多种类型的题。设第i天刷了Ai种类型的题目,问要怎么安排,才能安排全部题都刷完,而且这k天的Ai的和最大。

输入格式

1行为两个正整数 n和k,为题数和夏令营天数。

2行N个数,第i个数Ci表示第i题的类型。

输出格式

仅一行一个数,表示最优方案下,这k天的Ai的和的最大值。

样例输入

8 3
7 7 8 7 7 8 1 7

样例输出

6

样例解释

第一天做前三题,第二天做第4至第6题,剩余的两题第三天做。这样安排的话每天都能做到两种类型的题,加起来为6.

技术分享

这道题很容易想到O(nnk)的dpQAQ

但是正解需要线段树优化一波 

操作有区间求max和区间加

区间加的范围就是当前点到他颜色出现的前一次的位置

技术分享
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#define LL long long
using namespace std;
const int M=45007,N=1<<17; 
int read()
{
    char c;int s=0,t=1;
    while(!isdigit(c=getchar()))if(c==-)t=-1;
    do{s=s*10+c-0;}while(isdigit(c=getchar()));
    return s*t;
}
int T,n,m,c[M],cnt,L,R;
int f[M],last[M];
struct node{int v,pos;}e[M];
struct note{int h,mx;}tr[N];
bool cmp(node a,node b){return a.v<b.v;}
int max(int a,int b){return a>b?a:b;}
inline void up(int x){tr[x].mx=max(tr[x<<1].mx,tr[x<<1^1].mx);}
void build(int x,int l,int r){
    tr[x].h=0;
    if(l==r){
        tr[x].mx=f[l-1];
        return ;
    }
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1^1,mid+1,r);
    up(x);
}
void modify(int x,int l,int r){
    note&w=tr[x];
    if(L<=l&&r<=R){
        ++w.mx;
        ++w.h;
        return ;
    }
    note&lc=tr[x<<1],&rc=tr[x<<1^1];
    if(w.h){
        int a=w.h;
        lc.mx+=a;
        lc.h+=a;
        rc.mx+=a;
        rc.h+=a;
        w.h=0;
    }
    int mid=(l+r)>>1;
    if(L<=mid) modify(x<<1,l,mid);
    if(R>mid) modify(x<<1^1,mid+1,r);
    w.mx=max(lc.mx,rc.mx);
}
void push_max(int x,int l,int r){
    note&w=tr[x];
    if(w.mx<=T) return ;
    if(L<=l&&r<=R) return void(T=w.mx);
    if(w.h){
        note&lc=tr[x<<1],&rc=tr[x<<1^1];
        int a=w.h;
        lc.mx+=a;
        lc.h+=a;
        rc.mx+=a;
        rc.h+=a;
        w.h=0;
    }
    int mid=(l+r)>>1,ans=0;
    if(L<=mid) push_max(x<<1,l,mid);
    if(R>mid)  push_max(x<<1^1,mid+1,r);
}
int main()
{
    freopen("camp.in","r",stdin);
    freopen("camp.out","w",stdout);
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++) e[i].v=read(),e[i].pos=i;
    sort(e+1,e+1+n,cmp);
    c[e[1].pos]=++cnt;
    for(int i=2;i<=n;i++){
        if(e[i].v!=e[i-1].v) cnt++;
        c[e[i].pos]=cnt;
    }
    for(int k=1;k<=m;k++){
        build(1,1,n);
        memset(last,0,sizeof(last));
        for(int i=1;i<=n;i++){
            L=last[c[i]]+1; R=i;
            modify(1,1,n);
            L=1; R=i;
            T=0;
            push_max(1,1,n);
            f[i]=T;
            last[c[i]]=i;
        }
    }printf("%d\n",f[n]);
    return 0;
}
View Code

 

夏令营

标签:nbsp   ret   bsp   names   return   lin   nan   解释   线段   

原文地址:http://www.cnblogs.com/lyzuikeai/p/7343822.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!