题目描述

hzwer有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,…xk为开,其他开关为关时,密码锁才会打开。
他可以进行M种的操作,每种操作有一个size[i],表示,假如他选择了第i种的操作的话,他可以任意选择连续的size[i]个格子,把它们全部取反。(注意,由于黄金大神非常的神,所以操作次数可以无限>_<)
本来这是一个无关紧要的问题,但是,黄金大神不小心他的钱丢进去了,没有的钱他哪里能逃过被chenzeyu97 NTR的命运?>_< 于是,他为了虐爆czy,也为了去泡更多的妹子,决定打开这把锁。但是他那么神的人根本不屑这种”水题”。于是,他找到了你。
你的任务很简单,求出最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。

输入

第1行,三个正整数N,K,M,如题目所述。
第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。
第三行,M个正整数,表示size[i],size[]可能有重复元素。

输出

输出答案,无解输出-1。

样例输入

10 8 2
1 2 3 5 6 7 8 9
3 5

样例输出

2

提示

【样例输入2】
3 2 1
1 2
3
【样例输出2】
-1
【数据规模】
对于50%的数据,1≤N≤20,1≤k≤5,1≤m≤3;
对于另外20%的数据,1≤N≤10000,1≤k≤5,1≤m≤30;
对于100%的数据,1≤N≤10000,1≤k≤10,1≤m≤100。

首先最终状态是1 1 1 0 1 1 1 1 1 0 0

差分后为     1 0 0 1 1 0 0 0 0 1 0

这个差分结果可以换成括号序列的思想来理解

四个1分别出现在1 4 5 10四个位置,这是一个半闭半开区间,也就是说[1,4) [5,10)这两个区间内的数都必须是1

怎么办。

我们先处理出每一段区间全部变成1所需要的最少操作数

初始时所有的位置都是0,所以我们的任务是让[1,4) [5,10)这两个区间内的数变成1,而且操作数最少

所以考虑所有让这两个内的数变成1的情况,算出每种情况的操作数,然后取最小

把[1,4) [5,10)这两个区间内的数变成1就是把这两个区间内的元素取反

我们发现,取反这两个区间和取反[1,6) [4,10)这两个区间是等价的,所以这些数可以随机两两组合来进行变换,每次变换的加起来就是这种方案的操作数

k辣么小很明显用到状态压缩

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
#define inf 1000000000
#define N 10005
#define M 2000005
#define T 45
queue<int>q;
int n,k,m,num[N],x[N],sz[N],a[N],cnt,dis[N],d[][],f[M];
bool vis[N],mark[M];
void bfs(int x){
while(!q.empty())q.pop();
memset(vis,,sizeof(vis));
q.push(x);
vis[x]=;dis[x]=;
while(!q.empty()){
int now=q.front();q.pop();
for(int i=;i<=m;i++){
if(now+sz[i]<=n&&(!vis[now+sz[i]])){
vis[now+sz[i]]=;
dis[now+sz[i]]=dis[now]+;
q.push(now+sz[i]);
}
if(now-sz[i]>&&(!vis[now-sz[i]])){
vis[now-sz[i]]=;
dis[now-sz[i]]=dis[now]+;
q.push(now-sz[i]);
}
}
}
for(int i=;i<=n;i++)
if(num[i]){
if(!vis[i])d[num[x]][num[i]]=inf;
else d[num[x]][num[i]]=dis[i];
}
}
int dp(int x){
if(!x)return ;
if(mark[x])return f[x];
mark[x]=;f[x]=inf;
int st=;
for(int i=;i<=cnt;i++){
if(x&(<<(i-))){
if(!st)st=i;
else{
if(d[st][i]!=inf)
f[x]=min(f[x],dp(x^(<<(st-))^(<<(i-)))+d[st][i]);
}
}
}
return f[x];
}
int main(){
freopen("password.in","r",stdin);
freopen("password.out","w",stdout);
//freopen("Cola.txt","r",stdin);
scanf("%d%d%d",&n,&k,&m);
for(int i=;i<=k;i++){scanf("%d",&x[i]);a[x[i]]=;}
for(int i=;i<=m;i++)scanf("%d",&sz[i]);
for(int i=n+;i;i--)a[i]^=a[i-];
n++;
for(int i=;i<=n;i++){if(a[i])cnt++,num[i]=cnt;}
for(int i=;i<=n;i++)if(a[i])bfs(i);
dp((<<cnt)-);
if(f[(<<cnt)-]==inf)printf("-1");
else printf("%d",f[(<<cnt)-]);
return ;
}

【NOIP模拟赛】密码锁的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  10. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

随机推荐

  1. 7-10 括号匹配(25 分) 【STL】

    7-10 括号匹配(25 分) 给定一串字符,不超过100个字符,可能包括括号.数字.字母.标点符号.空格,编程检查这一串字符中的( ) ,[ ],{ }是否匹配. 输入格式: 输入在一行中给出一行字 ...

  2. IO多路复用之Reactor模式

    首先,我们来看看同步和异步. 在处理 IO 的时候,阻塞和非阻塞都是同步 IO.只有使用了特殊的 API 才是异步 IO. 接下来,我们来看看Linux下的三大同步IO多路复用函数 fcntl(fd, ...

  3. CLion提示can't find stdio.h等错误

    先上解决办法,启动参数如下: $ LANG=en_US.UTF-8 /path/to/clion.sh 查了好知久,竟然就由于编码的原因.可是Ubuntu已经设置为英文UTF-8,还是可以通过上面的方 ...

  4. POJ 2063 Investment (完全背包)

    A - Investment Time Limit:1000MS     Memory Limit:30000KB     64bit IO Format:%I64d & %I64u Subm ...

  5. Javascript类型转换的规则实例解析

    http://www.jb51.net/article/79916.htm 类型转换可以分为隐式转换和显式转换,所谓隐式转换即程序在运行时进行的自动转换,显式转换则是人为的对类型进行强制转换.Java ...

  6. 51nod 1533 && CF538F

    题目:难以简述,请传送门 神犇题解Ⅰ   神犇题解Ⅱ 好劲啊跪在地上..完全没接触过K叉树的性质.. 对于每个询问,我们并不关心叶节点,只关心其他的节点.而一个完整K叉树的内节点个数是O(n/k)的, ...

  7. github添加ssh公钥

    使用git作为版本维护工具非常方便,而且一般个人用github作为远端库就够用了.而一般git连接github的方式采用ssh的方法,http的会略微慢一些.所以为了方便一般会在github设置中添加 ...

  8. VC++中list::list的使用方法总结

    本文主题 这几天在做图像处理方面的研究,其中有一部分是关于图像分割方面的,图像目标在分割出来之后要做进一步的处理,因此有必要将目标图像的信息保存在一个变量里面,一开始想到的是数组,但是马上就发现使用数 ...

  9. java 基础 - 查找某个字串出现的次数及位置

    查找某个字串出现的次数及位置 public class search { public static void main(String[] args){ String str = "abc1 ...

  10. tensorflow 线性回归 iris

    线性拟合