• P4267 [USACO18FEB]Taming the Herd


    说实话感觉不是一道蓝题……感觉挺水的,不过为了水题解,水题就够了(其实是觉得思考的过程比较典型,记录一下)

    题解

    刚开始看这道题感觉上没什么思路,但是我们可以先考虑用 (O(n)) 的时间去枚举发生的出逃次数,再用 (O(n^2)) 的时间去计算每一个出逃次数的情况下不一致条目的最小值。

    现在我们考虑对于任意一个出逃次数 (d) ,我们如何计算。不妨设 (f_{i,j}) 表示到第 (i) 个点出逃过 (j) 次的最小差异值,易得 (dp) 方程为:

    [f_{i,j}=min(f_{k,j-1}+cost_{k+1,i}) ]

    其中 (cost_{l,r}) 是指:区间 (l) ~ (r) 为一次完整的出逃区间(即其中没有发生过一次出逃且 (l)(r+1) 发生了出逃)时的差异值。可以发现这个东西是可以 (O(n^2)) 预处理的。

    那么现在需要枚举 (i)(j)(k)(d),复杂度为 (O(n^4)) ,肯定是不行的,但是我们可以发现在处理略大的 (d) 值时其实是可以计算出较小的 (d) 值的,所以我们可以直接一起计算,就不需要枚举 (d) 了,复杂度就降为 (O(n^3)) ,可行了。

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    const int N=105;
    int n,a[N];
    int cost[N][N],f[N][N];
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;++i)
    	scanf("%d",&a[i]);
    	for(int i=1;i<=n;++i)
    	{
    		for(int j=i;j<=n;++j)
    		cost[i][j]=cost[i][j-1]+(a[j]!=j-i);
    	}
    	// for(int i=1;i<=n;++i)
    	// {
    	// 	for(int j=i;j<=n;++j)
    	// 	printf("%d %d %d
    ",i,j,cost[i][j]);
    	// }
    	memset(f,63,sizeof(f));
    	for(int i=1;i<=n;++i)
    	{
    		f[i][1]=cost[1][i];
    		for(int j=1;j<i;++j)
    		{
    			for(int k=1;k<=j;++k)
    			f[i][k+1]=min(f[i][k+1],f[j][k]+cost[j+1][i]);
    		}
    	}
    	for(int i=1;i<=n;++i)
    	printf("%d
    ",f[n][i]);
    	return 0;
    }
    
  • 相关阅读:
    CCF_ 201403-2_窗口
    CCF_201503-2_数字排序
    [loj3346]交换城市
    [cf516E]Drazil and His Happy Friends
    [cf505E]Mr. Kitayuta vs. Bamboos
    [loj3343]超现实树
    [loj3331]选课
    [loj3342]制作菜品
    [loj3156]回家路线
    [loj3339]美食家
  • 原文地址:https://www.cnblogs.com/Point-King/p/13616153.html
Copyright © 2020-2023  润新知