【洛谷P2072】宗|教问题【DP】

20 篇文章 0 订阅

在这里插入图片描述
题目链接

分析

这道题其实是两个问,逐一分析。

第一问只需要纯贪心就可以了,往后扫一遍,看看到哪里必须要分了,答案加一就行。

第二问一开始设的是 f [ i ] [ j ] f[i][j] f[i][j] 为前 i i i 个人分 j j j 段的最小危险值,发现转移的时候多划分段时没法判断是否+1,所以这个思路就夭折了。

因为肯定要对每个区间进行转移,所以可以预处理出区间 [ i , j ] [i,j] [i,j] 的宗|教种类数,这个是 n 2 n^2 n2 的时间。然后设 f [ i ] f[i] f[i] 为前 i i i 个人的最小危险值。

然后我们枚举分界点,如果 [ j , i ] [j,i] [j,i] 这个区间内的种类数量符合要求,那么就可以转移,分界点就在 j − 1 j-1 j1 这个地方。转移方程呼之欲出: f [ i ] = m i n ( f [ i ] , f [ j − 1 ] + s [ j ] [ i ] ) f[i]=min(f[i],f[j-1]+s[j][i]) f[i]=min(f[i],f[j1]+s[j][i])

答案显然为 f [ n ] f[n] f[n]

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int n,m,k,a[1010],f[1010],s[1010][1010];
int ans,tot,cnt=1,v[30];

int main()
{
	cin>>n>>m>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		if(!v[a[i]]) tot++;
		v[a[i]]=1;
		if(tot>k)
		{
			cnt++,tot=1;  
			for(int j=1;j<=20;j++) v[j]=0;
			v[a[i]]=1;
		} 
	}
	cout<<cnt<<endl;
	for(int i=1;i<=n;i++)
	{
		memset(v,0,sizeof(v));
		tot=0;
		for(int j=i;j<=n;j++)
		{
			if(!v[a[j]]) tot++;
			v[a[j]]=1;
			s[i][j]=tot;
		}
	}
	memset(f,0x3f,sizeof(f));
	f[0]=0;f[1]=1;
	for(int i=2;i<=n;i++)
	{
		for(int j=1;j<=i;j++)//枚举分界点 
		{
			if(s[j][i]>k) continue;
			f[i]=min(f[i],f[j-1]+s[j][i]);
		}
	//	cout<<f[i]<<' '; 
	}
	cout<<f[n];
	return 0;
} 

上次文章被和谐的我,瑟瑟发抖。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值