[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> ...
随机推荐
- Nginx代理后服务端使用remote_addr获取真实IP
直奔主题,在代理服务器的Nginx配置(yourWebsite.conf)的location /中添加: #获取客户端IP proxy_set_header Host $host; proxy_set ...
- 洛谷P2973 [USACO10HOL]赶小猪(高斯消元 期望)
题意 题目链接 Sol 设\(f[i]\)表示炸弹到达\(i\)这个点的概率,转移的时候考虑从哪个点转移而来 \(f[i] = \sum_{\frac{f(j) * (1 - \frac{p}{q}) ...
- Fatal error: Call to undefined function curl_init()解决办法
问题描述: 在Windows SERVER 2012RC 64 bit OS, php 5.6.3的环境下,搭建好了php运行环境.但是在调用 curl_init() 方法时却报错了. 检查了一下,p ...
- FineReport中如何实现自动滚屏效果
对于一些特殊的模板,可能为了展示的更加丰富.全面会在一个页面放置很多图表.表格等内容.由于内容过多,超出了浏览器窗口的大小导致内容展示不全的情况.这样我们就需要用到JS滚屏效果来解决,这里主要介绍在F ...
- create alter rename desc select update delete insert
conn scott/root;create table student (id number(3), name varchar2(10), sex char(2), sno number(3));a ...
- [转]How do you build a database?
非常简短的文字,却异常明了的说明了一个数据库管理系统的核心原理,原文来自原文. Its a great question, and deserves a long answer. Most datab ...
- LeetCode 之二叉树中序遍历(使用栈实现)
1.题目描述 2.使用栈实现难度大于使用递归实现 3.代码 vector<int> inorderTraversal(TreeNode* root) { // 非递归实现,借助栈 vect ...
- 记录今天客户的SQLSERVER启动不起来( 错误9003)的解决过程2013-11-26
记录今天客户的SQLSERVER启动不起来( 错误9003)的解决过程2013-11-26 今天一大早上班就接到客户的电话,说:SQLSERVER启动不起来,业务系统使用不了 于是我就使用QQ远程,帮 ...
- geogebra几何画图工具用法
1. intersectPath :该命令可以自动“算出”对应多边形的交汇区域 2. 静态文本可以指定到一个对象的中间这样将来动态变化对象大小时也不出现问题 3.export worksheet 4. ...
- 将DataRow赋值给model中同名属性
/// <summary> /// 将DataRow赋值给model中同名属性 /// </summary> /// <typeparam name="T&qu ...