【C++竞赛 A】xxx的项链

时间限制:2s 内存限制:64MB
问题描述
xxx有一个长度为n的宝石链,宝石有m种不同的颜色。xxx想截取其中连续的一段做一个项链。为了让项链更漂亮,xxx希望项链中的宝石包含所有颜色。
输入描述
第一行一个整数T(1≤T≤10)表示数据组数。
对于每组数据第一行两个整数n(1≤n≤〖10〗^5),m(1≤m≤30)
第二行n个整数C_1,C_2,…,C_n (0≤C_im)表示宝石链上每个宝石的颜色
输出描述
对于每组数据输出一行:一个整数,如果存在满足条件的方案,输出满足条件的最短长度,否则输出-1。
输入样例
2
4 3
0 1 2 0
4 3
0 1 1 0
输出样例
3
-1
样例解释
样例一: 截取[0 1 2],[1 2 0],[0 1 2 0]均满足条件,因此输出3
样例二: 没有满足条件的,输出-1

【题目链接】:
【题解】

枚举区间的左端点i,然后二分右端点;
用前缀和来记录到某个位置所有的颜色的贝壳的拥有情况;
右端点减去左端点的拥有情况就是中间的拥有情况;

【完整代码】

#include <bits/stdc++.h>
#define rep1(i,a,b) for (int i = a;i <= b;i++)
using namespace std;
#define pb push_back;

const int MAXN = 1e5+10;

int n,q,m;
int pre[MAXN][34],temp[34];

bool ok(int l,int r)
{
    int cnt = m;

    rep1(i,0,m-1)
    {
        temp[i] = pre[r][i]-pre[l-1][i];
        if (temp[i]==0)
        {
            cnt--;
            return false;
        }
    }
    if (cnt==m)
        return true;
    else
        return false;
}

int main()
{
    //freopen("D:\\rush.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while (T--)
    {
        int ans = 21e8;
        memset(pre,0,sizeof(pre));
        scanf("%d%d",&n,&m);
        rep1(i,1,n)
        {
            int x;
            scanf("%d",&x);
            pre[i][x]++;
            for (int j = 0;j<=m-1;j++)
                pre[i][j] += pre[i-1][j];
        }
        rep1(i,1,n)
        {
            int l = i,r = n,ans1=-1;
            while (l<=r)
            {
                int m = (l+r)>>1;
                if (ok(i,m))
                    ans1=m,r = m-1;
                else
                    l = m+1;
            }
            if (ans1!=-1)
                ans = min(ans,ans1-i+1);
        }
        if (ans==21e8)
            puts("-1");
        else
            printf("%d\n",ans);
    }
    return 0;
}
posted @ 2017-10-04 18:45  AWCXV  阅读(185)  评论(0编辑  收藏  举报