CodeForces - 1481E Sorting Books(贪心+dp)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 1481E Sorting Books(贪心+dp)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出一个长度为 n n n 的序列,每次操作可以将任意一本书放到序列的末尾,问最少需要操作多少次,才能使得相同的数字挨在一起

题目分析:不难看出,对每个位置的数都操作一次,是肯定能满足条件的,现在我们的目标是如何求得最优解

我们需要先转换一下模型,题目要求操作最少,我们可以转换为求哪些位置是不需要移动的。这样将剩下的位置按照一定次序进行操作,一定是可以达到目标的

对于某个数字 x x x 而言,设 l [ x ] l[x] l[x] r [ x ] r[x] r[x] 分别为 x x x 在原序列中第一次和最后一次出现的位置,同时 c n t [ x ] cnt[x] cnt[x] x x x 在整个序列出现的次数。假如 x x x 不需要移动的话,那么 [ l [ x ] , r [ x ] ] [l[x],r[x]] [l[x],r[x]] 这个区间内对 d p dp dp (哪些位置不需要移动)可以提供 c n t [ x ] cnt[x] cnt[x] 的贡献

不难看出,经过一系列迭代后,可以同时做出贡献的区间,必须是互不相交的,这一点是比较显然的

所以我们可以参考区间覆盖类 d p dp dp 的转移框架: d p [ i ] = d p [ j ] + [ j , i ] 区 间 的 贡 献 dp[i]=dp[j]+[j,i]区间的贡献 dp[i]=dp[j]+[j,i]

分析到此为止,本题其实就是一个中规中矩的 d p dp dp 而已,下面我想加入点自己的理解

如果继续下去, d p dp dp 的状态意义为,哪些位置是不需要移动的位置,那么我们必须限制递推是倒着来的,也就是 d p [ i ] dp[i] dp[i] 代表的是,区间 [ i , n ] [i,n] [i,n] 中,最多有多少个位置是不需要移动的

为什么要倒着来呢?因为本题的操作是需要将数字扔到序列的末尾, d p [ i ] dp[i] dp[i] 可以初始化为, [ i , n ] [i,n] [i,n] 中有多少个 a [ i ] a[i] a[i],这样初始化是很简单且可行的,可行性自己思考一下就能想明白了。但是与之相对的,如果 d p [ i ] dp[i] dp[i] 的递推是正向进行的,那就无法这样初始化了,所以递推下去相对困难

所以可以正着来吗?答案是肯定的,只不过需要对 d p dp dp 状态换个意义了, d p [ i ] dp[i] dp[i] 代表的是 [ 1 , i ] [1,i] [1,i] 中,每个数字所在的范围互不相交可以取到的最多的数字。如果想要求解上述的 “最多有多少个位置是不需要移动的”,还需要做进一步的转换,那就是需要求出区间 [ i + 1 , n ] [i+1,n] [i+1,n] 中,出现次数最多的数字。因为根据贪心来想,我们如果想要让 d p [ i ] dp[i] dp[i] 前面的部分作出贡献,就必须在 [ i + 1 , n ] [i+1,n] [i+1,n] 这段区间中固定下来一个 “不需要移动的数字” 才行。

其实也比较好理解,根据区间不相交的特点, d p [ i ] dp[i] dp[i] 已经求出了 [ 1 , i ] [1,i] [1,i] 中不需要移动的数字了,而我们还需要求出 [ i + 1 , n ] [i+1,n] [i+1,n] 中不需要移动的数字,贪心去想,显然是令出现次数最多的数字不动是最优的

代码:
倒着的

// Problem: E. Sorting Books
// Contest: Codeforces - Codeforces Round #699 (Div. 2)
// URL: https://codeforces.com/contest/1481/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
    T f=1;x=0;
    char ch=getchar();
    while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=f;
}
template<typename T>
inline void write(T x)
{
    if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int a[N],dp[N],l[N],r[N],cnt[N];
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n;
	read(n);
	for(int i=1;i<=n;i++) {
		read(a[i]);
		r[a[i]]=i;
		if(l[a[i]]==0) {
			l[a[i]]=i;
		}
	}
	for(int i=n;i>=1;i--) {
		dp[i]=dp[i+1];
		cnt[a[i]]++;
		if(i==l[a[i]]) {
			dp[i]=max(dp[i],dp[r[a[i]]+1]+cnt[a[i]]);
		} else {
			dp[i]=max(dp[i],cnt[a[i]]);
		}
	}
	cout<<n-dp[1]<<endl;
    return 0;
}

正着的:

// Problem: E. Sorting Books
// Contest: Codeforces - Codeforces Round #699 (Div. 2)
// URL: https://codeforces.com/contest/1481/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
    T f=1;x=0;
    char ch=getchar();
    while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=f;
}
template<typename T>
inline void write(T x)
{
    if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
int a[N],dp[N],l[N],r[N],cnt[N],mmax[N];
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n;
	read(n);
	for(int i=1;i<=n;i++) {
		read(a[i]);
		r[a[i]]=i;
		if(l[a[i]]==0) {
			l[a[i]]=i;
		}
	}
	for(int i=n;i>=1;i--) {
		cnt[a[i]]++;
		mmax[i]=max(mmax[i+1],cnt[a[i]]);
	}
	int ans=0;
	for(int i=1;i<=n;i++) {
		dp[i]=dp[i-1];
		if(i==r[a[i]]) {
			dp[i]=max(dp[i],dp[l[a[i]]-1]+cnt[a[i]]);
		}
		ans=max(ans,dp[i]+mmax[i+1]);
	}
	cout<<n-ans<<endl;
    return 0;
}

以上是关于CodeForces - 1481E Sorting Books(贪心+dp)的主要内容,如果未能解决你的问题,请参考以下文章

PHP未定义索引 - 排序

渲染层

clickhouse表引擎megerTree

clickhouse表引擎megerTree

从整数范围内搜索

ES6 - 从对象数组中删除重复项