CF838A
题目链接:http://codeforces.com/contest/838/problem/A
知识点: (void)
题目大意:
给一个 \(n \times m\) 的 01 矩阵,对于矩阵在 \(n \times m\) 这个范围外的可以都视为 0。将矩阵分为多个 \(k \times k\) 的小块 \((k>1, k \in Z)\),但是要变换矩阵上的元素,使每个小块都为 0 或者都为 1。求最少变换多少个元素可以满足要求。
解题思路:
用 vector<int> point[i] 记录第 \(i\) 行的 1 的位置。然后从 2 开始枚举 \(k\) 到 max(n,m),(剪枝:由某一个 \(k\) 得到的答案一定会优于或等于由 \(n \times k (n > 1, n \in Z)\) 得到的答案。因此,我们考虑完 \(k\) 之后,对于 \(2k, 3k...\) 这些就都不用考虑了,也就是说我们只需考虑 \(k\) 是素数的情况),对于每一个 \(k\),先遍历它对应的每一个小方块的左上角的点,然后遍历每个小方块的每一行,用 lower_bound() 找出这一行中位于对应小方块中的 1 的个数,加起来得到小方块中 1 的总数。然后每个小方块需要变换的元素数就是 min(\(k^2\) - num_of_one, num_of_one) (注:\(k^2\)-num_of_one = num_of_zero),加起来就是对应这个 \(k\) 对应的总变换数,最终答案就取那个最小值。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f, maxn = ;
int vis[maxn];
char st[maxn][maxn];
vector<int> point[maxn];
int main() {
int n, m;
int num = ;
scanf("%d%d", &n, &m);
for (int i = ; i<n; i++) scanf("%s", st[i]);
for (int i = ; i<n; i++)
for (int j = ; j<m; j++) {
if (st[i][j] == '') {
point[i].push_back(j);
num++; //1的总个数
}
}
int maxk = max(n, m), ans = num;
int temp, fail, tone;
for (int k = ; k <= maxk; k++) {
if (vis[k]) continue;
else {
for (int i = k; i <= maxk; i += k) vis[i] = ;
} temp = , fail = , tone = ;
for (int i = ; i<n; i += k) {
if (tone >= num || fail) break; //如果找出了所有的1,那么就没有必要再继续遍历下去了,其他的都是0
for (int j = ; j<m; j += k) { //定左上角
if (tone >= num || fail) break;
int one = ;
for (int z1 = ; z1<k&&i + z1<n; z1++) {
if (tone >= num || fail) break;
int l = lower_bound(point[i + z1].begin(), point[i + z1].end(), j) - point[i + z1].begin();
int r = lower_bound(point[i + z1].begin(), point[i + z1].end(), j + k) - point[i + z1].begin();
one += r - l;
tone += r - l;
}
temp += min(k*k - one, one);
if (temp >= ans) { //如果发现temp已经大于或等于我们目前已知的最佳答案,那么也没有必要继续下去了
fail = ;
break;
}
}
}
if (temp<ans) ans = temp;
}
printf("%d\n", ans); return ;
}
CF838A的更多相关文章
随机推荐
- 【用AI开挂的人生】5岁学编程,12岁进IBM
" 跟普通孩子比起来,14岁少年Tanmay Bakshi身上有无数光环: 5岁开始对计算机感兴趣 9岁发布了第1个iOSAPP 12岁成为IBM沃森最年轻的程序员 现任IBM Watson ...
- LFS资料和SSH远程登录全过程
LFS 即 Linux From Scratch, From Scratch的意思是"白手起家",即从0开始安装Linux,它的所有软件包都需要从源代码开始编译安装.这是通过实际动 ...
- centos 7.0运行docker出现内核报错解决方法
目前我这里docker是运行在centos 7.0系统里,使用1.5版本docker,最近一台服务器总是不定期死机,通过查看日志发现属于内核bug导致,报错信息如下 1 2 3 4 5 6 7 8 9 ...
- Linux下创建软、硬链接
在linux系统中,内核为每一个新创建的文件分配一个Inode(索引节点),每个文件都有唯一的inode号.文件属性保存在索引节点里,在访问文件时,索引节点被复制到内存,从而实现文件的快速访问. 链接 ...
- 上传组件Fine Uploader在ASP.NET中的应用
现如今,世面上流行着许多前端上传组件,例如:Uploadify(http://www.uploadify.com/),Fine Uploader,等等.这篇博客从头开始,介绍如何在ASP.NET MV ...
- 嵌入式Linux学习笔记(三) 字符型设备驱动--LED的驱动开发
在成功构建了一个能够运行在开发板平台的系统后,下一步就要正式开始应用的开发(这里前提是有一定的C语言基础,对ARM体系的软/硬件,这部分有疑问可能要参考其它教程),根据需求仔细分解任务,可以发现包含的 ...
- 最长公共子序列(Longest common subsequence)
问题描述: 给定两个序列 X=<x1, x2, ..., xm>, Y<y1, y2, ..., yn>,求X和Y长度最长的公共子序列.(子序列中的字符不要求连续) 这道题可以 ...
- 经典卷积神经网络算法(1):LeNet-5
.caret, .dropup > .btn > .caret { border-top-color: #000 !important; } .label { border: 1px so ...
- P2309(逆序对)
传送门 描述:给定一个序列长n,求多少子串和大于零. \(一开始一定会想到根据前缀和优化,枚举起点和中点O(n)解决\) \(那更高效的方法呢?实际上,我们上面就是要求S_i-S_j>0的数量\ ...
- Spring官网阅读(十八)Spring中的AOP
文章目录 什么是AOP AOP中的核心概念 切面 连接点 通知 切点 引入 目标对象 代理对象 织入 Spring中如何使用AOP 1.开启AOP 2.申明切面 3.申明切点 切点表达式 excecu ...