[luogu3943] 星空
题面
这个题目大意上是这样的:给定一个长度为n的01串, 其中只有k个0, 每次操作时, 从给定的m种长度中选择一种, 选择序列上长度为这种的进行反转操作, 求至少需要多少次操作使得整个串全变为1.
考虑状压dp, 枚举每一位出现情况, \(f[i]\)表示状态为\(i\)时最少需要翻转的方案数. 但是\(100pts\)的数据\(n\)有\(4e4\), 所以状压dp会达到一个令人恐怖的复杂度$ O(2 ^ {40000}) \(, 因为\)k\(较小, 考虑将问题的状压转化为与\)k\(相关. 由于需要更改整个数列, 从这个上面想到了什么优化的方法吗? 差分, 差分对于序列修改是一个比较实用的优秀方法, 我们可以设差分数组\)cha[i] = seq[i] - seq[i - 1]\(, 这样的话对序列\)[l, r]\(进行修改也就是\)cha[l] + 1, cha[r + 1] - 1\(, 这样优化后我们就将\)O(n)\(的序列修改变成了\)O(1)$的简单操作.
于是, 问题转化为这样: 给定一个长度为\(n\)的01串, 其中0的数目不超过\(2k\), 每次操作时, 从给定的\(m\)种给定的距离中选择一种, 选择序列上距离为这种的两个位同时取反, 求最少需要多少次能使得整个串变为1. 观察到, 如果一个位为0, 我们一定会选择一个方式去消去这个0, 要么是一个1和他进行操作, 此时可视为交换这两个数, 要么是一个0与他进行操作, 此时可视为这两个数同时消去, 这样我们又可以转化问题了
问题再次转化为这样:给定一个有n个点的图, 其中只有不超过\(2k\)的存在物品, 每次操作时, 从给定的m种距离中选择一种, 移动这个物品或与与他相距为这个距离的点同时消去, 问最少需要多少次操作使得所有的距离都消失.消去一个物品相当于将其中一个物品移动至另外一个物品的位置, 代价即为最少所需的步数, 同时, 每个点只有m条边, 我们发现这种操作可以用时间复杂度只有\(O(nmk)\)的\(BFS\)来解决.
问题转化为:图上有2k个物品, 选择其中两个可以消去, 分别有不同的代价, 求使得所有物品小时的最小代价, 至此, 我们成功将问题转化为与k相关的状压dp, 多好啊.
具体代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#define N 40005
using namespace std;
int n, k, m, cr[N], lth[100], pos[100], num[N], dis[20][20], f[1 << 20], step[N], cnt;
inline int read()
{
int x = 0, w = 1;
char c = getchar();
while(c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
return x * w;
}
inline void SPFA(int x)
{
memset(step, -1, sizeof(step));
queue <int> q;
q.push(pos[x]); step[pos[x]] = 0;
while(!q.empty())
{
int u = q.front(); q.pop();
for(int i = 1; i <= m; i++)
{
for(int j = -1; j <= 1; j += 2)
{
int end = u + lth[i] * j;
if(end <= 0 || end > n || step[end] != -1) continue;
step[end] = step[u] + 1; q.push(end);
}
}
}
for(int i = 1; i <= n; i++) if(num[i] != 0) dis[x][num[i]] = step[i];
}
int main()
{
// freopen("starlit.in", "r", stdin);
// freopen("starlit.out", "w", stdout);
n = read(); k = read(); m = read();
for(int i = 1; i <= k; i++) cr[read()] = 1;
for(int i = 1; i <= m; i++) lth[i] = read();
n++;
for(int i = 1; i <= n; i++) if(cr[i] ^ cr[i - 1]) { pos[++cnt] = i; num[i] = cnt; }
//记录下差分数组中为1(其实就是上面所说的为0)的位置.
memset(dis, -1, sizeof(dis));
for(int i = 1; i <= cnt; i++) SPFA(i);//BFS其实就是SPFA变一下.
memset(f, 0x3f, sizeof(f));
f[0] = 0;
for(int u = 0; u < (1 << cnt); u++)
for(int i = 1; i <= cnt; i++)
if(!(u & (1 << (i - 1))))
for(int j = i + 1; j <= cnt; j++)
if(!(u & (1 << (j - 1))))
if(dis[i][j] != -1)
{
int v = u | (1 << (i - 1)) | (1 << (j - 1));
f[v] = min(f[v], f[u] + dis[i][j]);
}//状压dp, 各位看官应该都看得懂吧...
printf("%d\n", f[(1 << cnt) - 1]);
return 0;
}
星空这道题与这道题有异曲同工之妙, 可以对比着做一下.
完
[luogu3943] 星空的更多相关文章
- 使用canvas绘制一片星空
效果图 五角星计算方式 代码 <body style="margin:0px;padding:0px;width:100%;height:100%;overflow:hidden;&q ...
- WPF星空效果
效果 前阵子看到ay的蜘蛛网效果和知乎的登录页背景,觉得效果很酷.自己也想写一个.于是写着写着就变成这样了.少女梦幻的赶脚有木有.我这有着一颗少女心的抠脚大汉 实现思路 分为两个部分: 1.星星无休止 ...
- 【Canvas】canva实例-星空、日出的效果
一.描述 模仿星空后黎明到来,日出的场景 二.代码 <!DOCTYPE html> <html> <head> <title></title> ...
- canvas星空和图形变换
图形变换. 一.画一片星空 先画一片canvas.width宽canvas.height高的黑色星空,再画200个随机位置,随机大小,随机旋转角度的星星. window.onload=function ...
- 使用JavaScript在Canvas上画出一片星空
随着Html5的迅猛发展,画布也变得越来越重要.下面我就写一个关于在canvas上画出一片星空的简单的代码的示例. 理论基础 初始化一个canvas,获得一个用于绘制图形的上下文环境context.并 ...
- 爬虫 - 动态分页抓取 游民星空 的资讯 - bs4
# coding=utf-8 # !/usr/bin/env python ''' author: dangxusheng desc : 动态分页抓取 游民星空 的资讯 date : 2018-08- ...
- js实现星空效果
本次主要是来实现上面的星空效果:在黑色的背景下面,有大小不一的星星在闪烁,当鼠标悬浮时,星星放大并旋转. 首先,我们需要一个大的夜空容器和放星星的容器: <!DOCTYPE html> & ...
- 【BZOJ-2864】战火星空 计算几何 + 最大流
2864: 战火星空 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 33 Solved: 14[Submit][Status][Discuss] D ...
- HTML5 Canvas ( 贝塞尔曲线, 一片星空加绿地 ) quadraticCurveTo, bezierCurveTo
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
随机推荐
- hdu 1430
魔板 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submiss ...
- asp.ne如何使用javascript去验证客户端信息,如果验证成功则送往服务器端处理,否则在客户端提示用户(不返回到服务器端处理)
一.问题 在网站一般都有很多地方需要用户去填写一些信息,然后用户点击提交,将信息送往后台储存到数据库中.在这一个过程我以前做法直接在button的click事件中来判断用户输入的数据是否完整和合法,虽 ...
- mysql if()
类似三元运算符 ,"男","女") 结果:
- Android View的事件分发机制和滑动冲突解决方案
这篇文章会先讲Android中View的事件分发机制,然后再介绍Android滑动冲突的形成原因并给出解决方案.因水平有限,讲的不会太过深入,只希望各位看了之后对事件分发机制的流程有个大概的概念,并且 ...
- scp远程传输文件和ssh远程连接
ssh使用方法 如果从一台linux服务器通过ssh远程登录到另一台Linux机器, 这种情况通常会在多台服务器的时候用到. 如用root帐号连接一个IP为192.168.1.102的机器,输入:“ ...
- Ubuntu 16.04下 - vi编辑器使用【backspace】无法删除
参考:https://blog.csdn.net/leiwangzhongde/article/details/83339589
- Django之modelform简介
在django中内置了form类和model类,当页面中的form值和model字段值完全一样时,此时可以通过model生成一个完全一样的form,Django中的modelForm就因此而生. 目标 ...
- 转载:eclipse 搭建SSH项目(第一篇)
第一篇:原文地址:http://blog.csdn.net/aaaaaaaa0705/article/details/6288431(虽然没有具体的例子,不过逻辑性强点,比较容易看懂) SSH框架是最 ...
- TableView的cell加载倒计时重用问题解决方案
TableView的cell加载倒计时重用问题解决方案 效果 说明 1. 写过类似需求的朋友一定知道,TableView上面加载倒计时功能会遇到复杂的重用问题难以解决 2. 本人提供一种解决思路,高效 ...
- Linux 用户和用户组详解
用户分类 超级用户:UID范围 0 root用户:uid=0(root) gid=0(root) groups=0(root) 普通用户:由管理员创建,UID范围(500-65535) --> ...