标签: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; }
标签:nbsp ret bsp names return lin nan 解释 线段
原文地址:http://www.cnblogs.com/lyzuikeai/p/7343822.html