BZOJ(本校) 2665 密码锁 - 思维&dp
2016-03-07 16:53
197 查看
Time Limit: 1s
Memory Limit: 512MB
【题目描述】
从前有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,…xk为开,其他开关为关时,密码锁才会打开。
你可以进行M种的操作,每种操作有一个size[i],表示,假如你选择了第i种的操作的话,你可以任意选择连续的size[i]个格子,把它们全部取反。
你的任务很简单,最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。
【输入格式】
第1行,三个正整数N,K,M,如题目所述。
第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。
第三行,M个正整数,表示size[i],size[]可能有重复元素。
【输出格式】
输出答案,无解输出-1。
【样例输入1】
10 8 2
1 2 3 5 6 7 8 9
3 5
【样例输出1】
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)的位置设1
原问题<=>将所有点两两配对(费用是一个点通过各个size的操作走到另一个点的最少操作次数),且费用和最小。(费用的处理用bfs搞最短路)
注意到k的范围很小[1,10],所以这样的点不超过20个,想到状压dp(s为一个20位的2进制数,表示要处理的点的集合):
dp[s]=min(dp[s], dp[s-(1<< i)-(1<< j)]+dist(i,j) ),i是新加入集合的点(即拿来配对的点),j是s中有的除i以外的点。
Memory Limit: 512MB
【题目描述】
从前有一把密码锁,由N个开关组成。一开始的时候,所有开关都是关上的。当且仅当开关x1,x2,x3,…xk为开,其他开关为关时,密码锁才会打开。
你可以进行M种的操作,每种操作有一个size[i],表示,假如你选择了第i种的操作的话,你可以任意选择连续的size[i]个格子,把它们全部取反。
你的任务很简单,最少需要多少步才能打开密码锁,或者如果无解的话,请输出-1。
【输入格式】
第1行,三个正整数N,K,M,如题目所述。
第2行,K个正整数,表示开关x1,x2,x3..xk必须为开,保证x两两不同。
第三行,M个正整数,表示size[i],size[]可能有重复元素。
【输出格式】
输出答案,无解输出-1。
【样例输入1】
10 8 2
1 2 3 5 6 7 8 9
3 5
【样例输出1】
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)的位置设1
原问题<=>将所有点两两配对(费用是一个点通过各个size的操作走到另一个点的最少操作次数),且费用和最小。(费用的处理用bfs搞最短路)
注意到k的范围很小[1,10],所以这样的点不超过20个,想到状压dp(s为一个20位的2进制数,表示要处理的点的集合):
dp[s]=min(dp[s], dp[s-(1<< i)-(1<< j)]+dist(i,j) ),i是新加入集合的点(即拿来配对的点),j是s中有的除i以外的点。
#include<cstdio> #include<queue> #include<algorithm> #include<cassert> using namespace std; #define MAXN 10000 #define MAXK 10 #define MAXM 100 #define MAXST 1048576 #define INF 2000000000 int n,k,m,light[MAXN+10],siz[MAXM+10],id[MAXN+10],edge[MAXK*2+10][MAXK*2+10],cntp; int f[MAXST+10],dist[MAXN+10],g[MAXST+10]; bool vis[MAXN+10]; void read() { int x; scanf("%d%d%d",&n,&k,&m); for(int i=1;i<=k;i++){ scanf("%d",&x); light[x]=1; } for(int i=n+1;i>=1;i--) light[i]^=light[i-1]; for(int i=1;i<=n+1;i++) if(light[i]) id[i]=++cntp; for(int i=1;i<=m;i++) scanf("%d",&siz[i]); sort(siz+1,siz+m+1); m=unique(siz+1,siz+m+1)-(siz+1); } void Bfs(int s) { int u; for(int i=1;i<=n+1;i++) dist[i]=INF,vis[i]=false; queue<int> que; que.push(s); vis[s]=true,dist[s]=0; while(!que.empty()){ u=que.front(); que.pop(); for(int i=1;i<=m;i++) if(u+siz[i]<=n+1&&!vis[u+siz[i]]){ vis[u+siz[i]]=true; dist[u+siz[i]]=dist[u]+1; que.push(u+siz[i]); } for(int i=1;i<=m;i++) if(u-siz[i]>=1&&!vis[u-siz[i]]){ vis[u-siz[i]]=true; dist[u-siz[i]]=dist[u]+1; que.push(u-siz[i]); } } for(int i=1;i<=n+1;i++){ if(!light[i]) continue; if(vis[i]) edge[id[s]][id[i]]=dist[i]; else edge[id[s]][id[i]]=INF; } } void Getdist() { for(int i=1;i<=n+1;i++) if(light[i]) Bfs(i); } void DP() { f[0]=0; for(int s=1;s<(1<<cntp);s++){ //这样枚举s,s从左往右的第一个是1的位置就是新增加的元素(即拿去匹配的元素) g[s]=g[s>>1]+(s&1); f[s]=INF; if(g[s]%2) continue; int newu=-1; for(int i=0;i<cntp;i++){ if(s&(1<<i)){ if(newu==-1) newu=i; else{ if(f[s-(1<<newu)-(1<<i)]!=INF) f[s]=min(f[s],f[s-(1<<newu)-(1<<i)]+edge[newu+1][i+1]); } } } } printf("%d\n",f[(1<<cntp)-1]==INF?-1:f[(1<<cntp)-1]); } int main() { read(); Getdist(); DP(); return 0; }
相关文章推荐
- 安卓环境中遇到的问题
- iOS同步后couldn't load project
- 如何删除xcode项目中不再使用的图片资源
- 偷师饿了么:怎样用HTTP/2优化iOS APP网络层次架构?
- android动画速率Interpolator类的一些认识
- 点击变色以及按Ctrl建多选
- BLE 包结构及传输速率
- Elasticsearch 设置_mapping
- Servlet之初识
- JavaScript之变量
- android edittext 点击回车会响应两次的解决方案
- 游戏批量合成道具算绑定道具的数量算法
- android-studio快捷键(md格式)
- iOS安全系列之:HTTPS
- SQL常用语句----基础
- HihoCoder 1270 建造基地(完全背包)
- 判断“回文”
- 4099: [Usaco2015 Open]Trapped in the Haybales|并查集|乱搞
- 单例模式 静态属性 实例属性
- HDU 4527 小明系列故事——玩转十滴水