题面

​ 这个题目大意上是这样的:给定一个长度为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] 星空的更多相关文章

  1. 使用canvas绘制一片星空

    效果图 五角星计算方式 代码 <body style="margin:0px;padding:0px;width:100%;height:100%;overflow:hidden;&q ...

  2. WPF星空效果

    效果 前阵子看到ay的蜘蛛网效果和知乎的登录页背景,觉得效果很酷.自己也想写一个.于是写着写着就变成这样了.少女梦幻的赶脚有木有.我这有着一颗少女心的抠脚大汉 实现思路 分为两个部分: 1.星星无休止 ...

  3. 【Canvas】canva实例-星空、日出的效果

    一.描述 模仿星空后黎明到来,日出的场景 二.代码 <!DOCTYPE html> <html> <head> <title></title> ...

  4. canvas星空和图形变换

    图形变换. 一.画一片星空 先画一片canvas.width宽canvas.height高的黑色星空,再画200个随机位置,随机大小,随机旋转角度的星星. window.onload=function ...

  5. 使用JavaScript在Canvas上画出一片星空

    随着Html5的迅猛发展,画布也变得越来越重要.下面我就写一个关于在canvas上画出一片星空的简单的代码的示例. 理论基础 初始化一个canvas,获得一个用于绘制图形的上下文环境context.并 ...

  6. 爬虫 - 动态分页抓取 游民星空 的资讯 - bs4

    # coding=utf-8 # !/usr/bin/env python ''' author: dangxusheng desc : 动态分页抓取 游民星空 的资讯 date : 2018-08- ...

  7. js实现星空效果

    本次主要是来实现上面的星空效果:在黑色的背景下面,有大小不一的星星在闪烁,当鼠标悬浮时,星星放大并旋转. 首先,我们需要一个大的夜空容器和放星星的容器: <!DOCTYPE html> & ...

  8. 【BZOJ-2864】战火星空 计算几何 + 最大流

    2864: 战火星空 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 33  Solved: 14[Submit][Status][Discuss] D ...

  9. HTML5 Canvas ( 贝塞尔曲线, 一片星空加绿地 ) quadraticCurveTo, bezierCurveTo

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

随机推荐

  1. Spring Boot学习笔记(六)mybatis配置多数据源

    application.properties #数据库配置 #数据源类型 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource # ...

  2. Java:使用DOM4j来实现读写XML文件中的属性和元素

    DOM4可以读取和添加XML文件的属性或者元素 读取属性: public static void ReadAttributes() throws DocumentException { File fi ...

  3. MarkDownPad 专业汉化破解

     解压Pa_ttrar 运行Pa_ttrar.exe    点击下边第一个按钮“patch”——>弹出窗选择“YES”  选择“YES”后会选择一个文件,找到“C:\Users\用户名\AppD ...

  4. 简洁php的MVC框架

    一.文件结构 建立3个文件夹 controller文件夹存放控制器文件 view文件夹存放视图文件 model文件夹存放数据文件 建立1个index.php 作为唯一入口 二.控制器 我们在contr ...

  5. 转:Windows下PHP7安装Redis和Redis扩展phpredis

    原文地址:Windows下PHP7安装Redis和Redis扩展phpredis Windows下PHP7安装Redis和Redis扩展phpredis 2016-06-08 17:53:00 标签: ...

  6. C# 新建文档CreateNewDocument

    // Copyright 2010 ESRI// // All rights reserved under the copyright laws of the United States// and ...

  7. RxJava + Retrofit完成网络请求

    1.前言 本文基于RxJava.Retrofit的使用,若是对RxJava或Retrofit还不了解的简友可以先了解RxJava.Retrofit的用法再来看这篇文章. 在这片文章之前分别单独介绍过R ...

  8. 【日常记录】Unity3D 中的 Surface Shader 是不支持在 Pass中使用的,因为自动生成了 Pass

    如题 搞了好久,一直报错: Shader error in 'custom_outline_effect': Parse error: syntax error, unexpected TOK_PAS ...

  9. C#代码实现在控制台输入密码显示星号

    在控制台输入的内容C#默认按照字符串进行处理,如果直接让用户一次输入完毕就很难实现 显示星号的功能.但是如果让用户一次只能输入一个字符就,在将用户输入的字符替换为星号就可以实现了! 首先,C#中能让用 ...

  10. 执行SQL的DbHelperSQL

    using System; using System.Collections; using System.Collections.Specialized; using System.Data; usi ...