Codeforces 367D Sereja and Sets 位运算暴力

题目大意:

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


大致思路:

记录下每个数出现在第几个集合当中然后遍历一遍[1, n], 对于其中所有连续的长度为d的连续子区间都记录一下出现了哪个集合中的数, 那么显然对于一个长度为d的子区间如果一个选出的集合组中没有包含这个长度为d的区间当中的任何一个集合的话, 选出来的哪一组集合一定不是解, 如果把所有的出现在这个长度为d的子区间当中的集合都出去之后留下来的极大集合组标记为not answer的话, 所有这个极大集合组的子集都不是解, 于是利用这个单调性在使用状态压缩暴力枚举的时候如果当前这个是bad choice, 就用这个最大的bad choice向下标记小的bad choice, 这样保证的暴力过程当中的拓扑序, 剩下的就可以直接循环从大到小枚举状态了

感觉这个拓扑序还是挺不错的


代码如下:

Result  :  Accepted     Memory  :  1424 KB     Time  :  78 ms

/*
 * Author: Gatevin
 * Created Time:  2015/3/23 17:27:48
 * File Name: Chitoge_Kirisaki.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

int d, n, m, belong[100010], cnt[20];
bool no[1 << 20];

int main()
{
    scanf("%d %d %d", &n, &m, &d);
    for(int i = 0; i < m; i++)
    {
        int num, tmp;
        scanf("%d", &num);
        while(num--)
        {
            scanf("%d", &tmp);
            belong[tmp] = i;
        }
    }
    for(int i = 1; i <= n; i++)
    {
        if(i > d) cnt[belong[i - d]]--;
        cnt[belong[i]]++;
        if(i >= d)
        {
            int sta = 0;
            for(int j = 0; j < m; j++)
                if(!cnt[j])
                    sta |= (1 << j);
            no[sta] = 1;
        }
    }
    int ans = m + 1;
    for(int i = (1 << m) - 1; i >= 0; i--)
    {
        if(no[i])
        {
            for(int j = 0; j < m; j++)
                if(i & (1 << j))
                    no[i ^ (1 << j)] = 1;
        }
        else
            ans = min(ans, __builtin_popcount(i));//__builtin_popcount返回其二进制中1的个数
    }
    printf("%d\n", ans);
    return 0;
}


你可能感兴趣的:(位运算,codeforces,and,暴力,sets,Sereja,367D)