ZOJ 3790 Consecutive Blocks【离散化】【贪心】

题目链接

http://icpc.moe/onlinejudge/showProblem.do?problemCode=3790

思路

意思就是,给你一个数字序列,现在你能从中删去k个数字,问你能得到的最大连续的相同数字长度是多少。

我们可以把每个数字出现的位置记录到一个数组里(设为a[x]),然后设两个哨兵lr,一开始l=r=a[x][0] 然后开始移动,每次先看看k够不够,够的话先把r往右移一格,k减去两个数的距离,否则把l往左移一格,k加上两个数的距离,这样一来整体的复杂度就是O(sizeof(a[x]))级别的。然后对所有的x取最大值就行了,总复杂度为O(N),N为序列元素个数。

之所以可以这么移是因为,假设用 n2 暴力,每次r移完后,l往前移一格,然后r从l开始往后,但这从l到原来r的位置都是白算了,因为长度不可能会大于原来的r-l,所以r可以从原来的位置开始移动。

但这样还有一个小问题,元素最大可能到 109 ,数组开不下,怎么办?仔细观察发现,N最大只有 105 ,所以完全可以把这 109 映射到 105 内,这样数组就开的下了。

AC代码

#include <iostream>
#include <iomanip>
#include <fstream>
#include <sstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <functional>
#include <numeric>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <vector>
#include <queue>
#include <deque>
#include <list>
using namespace std;

map<int,int>mp;
vector<int> v[100000+100];
int main() {
    int n,k;
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        for(int i=0 ; i<n; ++i)
        {
            v[i].clear();
        }
        mp.clear();
        int p=0;
        for(int i=0 ; i<n ; ++i)
        {
            int t;
            scanf("%d",&t);
            if(!mp.count(t))
            {
                mp[t]=p++;
            }
            v[mp[t]].push_back(i);
        }
        int ans=1;
        for(int i=0 ; i<p ;++i)
        {
            int l=0,r=0;
            int size=v[i].size();
            while(r<size)
            {
                if(v[i][r]-v[i][l]-1-(r-l-1)<=k)
                {
                    ans=max(r-l+1,ans);
                    r++;
                }
                else
                    l++;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(ACM)