CTU OPEN 2017 Ice cream samples /// 尺取法

题目大意:

给定n k

接下来n行 给定n个摊位的冰淇淋信息

首先给一个t 表示这个摊位有t个冰淇淋 接下来t个数表示对应冰淇淋的品种

走到连续的几个摊位 会买下走过的摊位的所有的冰淇淋

求 要买下所有k个品种的冰淇淋 最少需要买下多少冰淇淋

 

尺取法

L R指针移动 表示走过L~R的摊位

利用cnt[]记录品种信息

#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define INF 0x3f3f3f3f
#define mem(i,j) memset(i,j,sizeof(i))
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
#define gcd(i,j) __gcd(i,j);
const int N=1e6+5;
const int mod=1e9+7;
const double eps=1e-8;

int n,k;
vector<int>v[N]; // v[i]中存有i摊位有的品种
int cnt[N]; // cnt[i]为此时区间中i品种的数量

int main()
{
    while(~scanf("%d%d",&n,&k)) {
        inc(i,1,n) v[i].clear();
        inc(i,1,k) cnt[i]=0;
        inc(i,1,n) {
            int t; scanf("%d",&t);
            while(t--) {
                int m; scanf("%d",&m);
                v[i].push_back(m);
            }
        }
        int ans=INF;
        int L=1,R=1,num=0,all=0;
        while(L<=n) {
            int len=v[R].size();
            all+=len;
            inc(i,0,len-1) // 记录这个摊位的品种
                if(cnt[v[R][i]]++==0) num++;
            R= (R+1)%n==0 ? n:(R+1)%n;
            if(R==L && num<k) break; // 说明所有摊位都无法凑齐所有品种
            while(num==k && L<=n) { // 找到了k个品种
                ans=min(ans,all); 
                len=v[L].size();
                inc(i,0,len-1) // 移动左端 可能有富余
                    if(--cnt[v[L][i]]==0) num--;
                L++; all-=len;
            }
        }
        if(ans==INF) printf("-1\n");
        else printf("%d\n",ans);
    }

    return 0;
}
View Code

 

posted @ 2019-03-17 15:15  _Jessie  阅读(143)  评论(0编辑  收藏  举报