Codeforces 1423 L. Light switches —— 折半?搜索

82 篇文章 1 订阅

This way

题意:

现在有n盏灯,每开关控制了一些灯,按一下这些灯的状态就会翻转。现在每次有一些灯开着,问你让所有灯熄灭的最少需要按的开关数量是多少。

题解:

那么这道题目的开关数只有30,很容易想到折半搜索,但是开关数有1000个,就算用了bitset运算,时间复杂度也是不够的,但是我们可以知道,起始状态是固定的,那么我们只需要这个折半偏一点点,起始状态给个20个开关,然后每次只需要搜后面10个开关,时间复杂度就允许了。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5,M=(1<<20)+5,K=(1<<10)+5;
unordered_map<bitset<N>,int>mp;
bitset<N>b[N],tmp,tt;
int main()
{
    int n,m,q;
    scanf("%d%d%d",&n,&m,&q);
    for(int i=0;i<m;i++){
        int k,x;
        scanf("%d",&k);
        while(k--){
            scanf("%d",&x);
            b[i].set(x);
        }
    }
    int num=min(m,20),mx=(1<<num)-1;
    //mp[0]=0;
    for(int i=0;i<=mx;i++){
        tmp.reset();
        int sum=0;
        for(int j=0;j<num;j++){
            if(i&(1<<j)){
                tmp^=b[j];
                sum++;
            }
        }
        if(!mp.count(tmp)||mp[tmp]>sum)
            mp[tmp]=sum;
    }
    while(q--){
        int k,x;
        scanf("%d",&k);
        tmp.reset();
        while(k--){
            scanf("%d",&x);
            tmp.set(x);
        }
        if(m<=20){
            if(mp.count(tmp))printf("%d\n",mp[tmp]);
            else printf("-1\n");
            continue;
        }
        num=m-20,mx=(1<<num)-1;
        int ans=N;
        for(int i=0;i<=mx;i++){
            tt=tmp;
            int sum=0;
            for(int j=0;j<num;j++){
                if(i&(1<<j)){
                    tt^=b[j+20];
                    sum++;
                }
            }
            if(mp.count(tt))
                ans=min(ans,mp[tt]+sum);
        }
        printf("%d\n",ans==N?-1:ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值