Codeforces 367D Sereja and Sets 题解&代码

本文介绍了一种通过二进制枚举和递归方法解决区间覆盖问题的算法。旨在寻找最少数量的集合,使得这些集合中的元素能覆盖指定长度内的每一个连续区间。文章详细展示了如何实现这一算法,并给出了具体的代码实现。

题意:有1-n共n个正整数被分成了m个非空集合(m个集合的并是n个正整数,交总是空集),从m个集合中选最少的集合数,使得对于给定的d,选出的集合中的所有数从小到大排列后满足对于[1, n]这个区间中任意长度为d的连续子区间都至少有一个数在选出的集合中 (1<=d<=n<=100000,1<=m<=20)

这个题意是看网上的转化= =原题意比这个抽象很多,这样转化之后整个问题都简化了
思路:
如果要对于每个区间[i,i+d-1](长度为d的子区间)都存在有一组集合使得集合组中至少存在一个元素存在于区间中;那么如果对于某个区间,某个集合组的数全部不存在于该区间,这个集合组以及这个集合组的子集一定都不满足条件。
然后二进制枚举集合组,同时向下递推false集合组的子集
对于false数组没有标记的所有情况,统计集合组中包含集合的个数,找到包含集合数最少的值。

#include<iostream>
#include<stdio.h>
using namespace std;
const int maxn=100005;
int n,m,d,cnt,num,ans,sta,a[1<<21],k[maxn],fal[1<<21];
int main(void)
{
    scanf("%d%d%d",&n,&m,&d);
    for(int i=0;i<m;i++)
    {
        scanf("%d",&cnt);
        while(cnt--)
        {
            scanf("%d",&num);
            k[num]=i;
        }
    }
    ans=m+1;
    for(int i=1;i<d;i++)
        a[k[i]]++;
    for(int i=d;i<=n;i++)
    {
        if(i>d)a[k[i-d]]--;
        a[k[i]]++;sta=0;
        for(int j=0;j<m;j++)
            if(!a[j])sta|=(1<<j);
        fal[sta]=1;
    }
    for(int i=(1<<m)-1;i>=0;i--)
    {
        if(fal[i])
        {
            for(int j=0;j<m;j++)
            if(i & (1<<j))fal[i^(1<<j)]=1;
        }
        else
        {
            cnt=0;
            for(int j=0;j<m;j++)
                if(i & (1<<j))cnt++;
            ans=min(ans,cnt);
        }
    }
    printf("%d\n",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值