武大校赛资格赛 最小矩阵覆盖

Problem 1567 - D - Sloth's Angry
Time Limit: 1000MS   Memory Limit: 65536KB   
Total Submit: 248  Accepted: 88  Special Judge: No
Description
A forest is full of sloths, they are so eager for tree leaves and as a result, very angry.
We assume that the forest is a map of N * M grids, and each of the gird is an empty land or contains a big sloth. It’s guaranteed that the sequence of the sloth is a continuous segment from the leftmost column for every row. ( You may consider that the number of columns M is infinite ).
As a sloth lover, you want to feed all the sloths as quick as possible. Every second you may select a rectangle area of the grids which only contains sloths and feed all the sloths there.
What’s the minimum time required to meet all the sloths’ needs in the forest?
Input
First line of each case contains one numbers N.(1≤  n ≤ 1 000).

The following line contains N numbers Ai, each describing the length of continuous sloths sequence from the left most column in every row. ( 1 <= Ai <= 10^9 )
Output
Output the answer on a single line for each case.
Sample Input
4
3 4 5 5
Sample Output
3
Hint

The distributing situation of the sloths in the sample is as follow:

SSS

SSSS

SSSSS

SSSSS

And you can choose three rectangles to cover it.

 

恩。很显然的贪心,证明如下:

设还未选择的子矩阵,即剩下的步骤中的最优解,组成了一个集合,每次尝试确定这个集合中左端点最小的一个矩阵,并把它从集合里删去。

这样我们可以发现,某行树懒是否被完全喂饱,取决于当前选择的矩阵是否包含该行的最右边的端点。换句话说,如果不包含这个最右边的端点,那么我们称这次的操作对该行树懒并不产生实质影响。

如此,显然可以得到一个贪心策略:每次选择整个区间中每行右端点中最小的值,并利用一次操作去掉这些行。然后继续划分下去。

#include<algorithm>
#include<iostream>
#include<limits.h>
#include<stdlib.h>
#include<string.h>
#include<cstring>
#include<iomanip>
#include<stdio.h>
#include<bitset>
#include<cctype>
#include<math.h>
#include<string>
#include<time.h>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<list>
#include<map>
#include<set>

#define LL long long

using namespace std;
const LL mod = 1e9 + 7;
const double PI = acos(-1.0);
const int M = 1005;

int a[M];

LL work(int l, int r, int x)
{
    int last = l, mn = a[l];
    LL len = r - l + 1, sum;
    for(int i = l; i <= r; ++i)
        mn = min(mn,a[i]);
    sum = 1;
    for(int i = l; i <= r; ++i){
        if(a[i] == mn){
            if(last < i)
                sum += work(last,i - 1,mn);
            last = i + 1;
        }
    }
    if(last <= r)
        sum += work(last,r,mn);
    return min(len,sum);
}
int main()
{
    int n;
    while( cin >> n ){
        for(int i = 1; i <= n; ++i)
            scanf("%d",&a[i]);
        int flag = 2;
        for(int i = 2; i <= n; ++i){
            if(a[i] == a[i - 1])
                continue;
            a[flag++] = a[i];
        }
        LL ans = work(1,flag - 1,0);
        cout << ans << endl;
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值