CodeForces
来源:互联网 发布:矩阵的秩8个性质及证明 编辑:程序博客网 时间:2024/06/03 13:06
题目大意:
给你一串数(n<35000),让你把他们分成 k(k<50)段,每一段的值定义为这一段里不同数字的个数。现在让你求出一种划分方式,使得这 k 个区间段的值的和最大。
分析:
定义状态:
dp[ i ][ j ] 表示把前 j 个分成 i 份能得到的最大值;dif[ i ][ j ] 表示区间 [ i , j ] 里面不同的数的个数。
状态转移方程:
关于优化时间复杂度:
如此看来时间复杂度应该是O(n^2 k),这么搞怕是要超时。所以要想办法利用之0前得到的结果。
对于每一次处理分成 k 段时求解 dp[ k ][ k ] ~ dp[ k ][ n ] 的值,创建一颗线段树,定义其每个节点 tree[ i ] 表示的意义为:第 i 个点到第 j 个点的区间中不同的数的个数+dp[ k-1 ][ i-1 ]。这样就在一边维护 tree[ j ] 的同时就确定了 dp[ k ][ j ] 的值。
代码:
#include<bits/stdc++.h>#define MAXN 35050using namespace std;int tree[MAXN<<2];//记录a[i]到a[j]的最大值。int n,k;int a[MAXN];int pre[MAXN];//pre[i]表示a[i]的前一个和他相同的数的下标。int last[MAXN];int temp[MAXN];int lazy[MAXN<<2];int dp[60][MAXN]={0};void Push_up(int x){ tree[x]=max(tree[x<<1],tree[x<<1|1]);}void Build(int l,int r,int rt){ if(l==r) { tree[rt]=temp[l]; return; } int mid=(l+r)>>1; Build( l , mid , rt<<1 ); Build( mid+1 , r , rt<<1|1 ); Push_up( rt );}void Push_down(int rt){ if(lazy[rt]) { lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; tree[rt<<1]+=lazy[rt]; tree[rt<<1|1]+=lazy[rt]; lazy[rt]=0; }}void Add_interval(int L,int R,int C,int l,int r,int rt){ if(L<=l&&r<=R) { tree[rt]+=C; lazy[rt]+=C; return; } int mid=(l+r)>>1; Push_down(rt); if(L<=mid)Add_interval(L,R,C,l,mid,rt<<1); if(R>mid)Add_interval(L,R,C,mid+1,r,rt<<1|1); Push_up(rt);}int Qurey_interval(int L,int R,int l,int r,int rt){ if(L<=l&&R>=r)return tree[rt]; int mid=(r+l)>>1; Push_down(rt); int ans=0; if(L<=mid)ans=max(ans,Qurey_interval(L,R,l,mid,rt<<1)); if(R>mid)ans=max(ans,Qurey_interval(L,R,mid+1,r,rt<<1|1)); Push_up(rt); return ans;}void Add_point(int L,int C,int l,int r,int rt){ if (l==r) { tree[rt]+=C; return; } int mid=(l+r)>>1; Push_down(rt); if (L<=mid) Add_point(L,C,l,mid,rt<<1); else Add_point(L,C,mid+1,r,rt<<1|1); Push_up(rt);}int main(){ scanf("%d%d",&n,&k); memset(last,0,sizeof(last)); memset(pre,0,sizeof(pre)); memset(temp,0,sizeof(temp)); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); pre[i]=last[a[i]]; last[a[i]]=i; } for(int i=1;i<=k;i++) { memset(tree,0,sizeof(tree)); memset(lazy,0,sizeof(lazy)); Build(1,n,1); for(int j=1;j<=n;j++) { Add_interval( pre[j]+1 , j , 1 , 1 , n , 1 ); if(i<=j) { dp[i][j]=Qurey_interval(1,j,1,n,1);//取 [ 1 , j ] 的最大值。-+ temp[j+1]=dp[i][j]; } //cout<<temp[j]<<" "; } //cout<<endl; } int ans=0; printf("%d\n",dp[k][n]);}
阅读全文
0 0
- codeforces~~~
- Codeforces
- codeforces
- Codeforces
- codeforces
- codeforces
- Codeforces
- Codeforces
- CodeForces
- CodeForces
- CodeForces
- CodeForces
- CodeForces
- Codeforces
- Codeforces
- Codeforces
- Codeforces
- Codeforces
- 【jzoj5237】【GDOI2018模拟8.7】【最长公共子序列 】【动态规划】
- UVA796 Critical Links (tanjar求桥)
- 简单使用百度语音合成、工具类直接使用
- LintCode49
- 进程通信值pipe管道
- CodeForces
- Leetcode Median of Two Sorted Arrays
- Appium官网Introduction
- hdu3507Print Article(斜率)
- JZOJ 5234. 【NOIP2017模拟8.7A组】外星人的路径
- SQL的四种连接-左外连接、右外连接、内连接、全连接、交叉连接
- kickstart笔记
- Eclipse&&idea快捷键功能
- HDU-3666 THE MATRIX PROBLEM(差分约束系统判断存在与否+特殊剪枝)