codeforces838A Binary Blocks

来源:互联网 发布:知乎lolfaker 编辑:程序博客网 时间:2024/06/05 08:44
                                                                                                                               A. Binary Blocks

You are given an image, that can be represented with a 2-d n by m grid of pixels. Each pixel of the image is either on or off, denoted by the characters "0" or "1", respectively. You would like to compress this image. You want to choose an integer k > 1 and split the image into k by k blocks. If n and m are not divisible by k, the image is padded with only zeros on the right and bottom so that they are divisible by k. Each pixel in each individual block must have the same value. The given image may not be compressible in its current state. Find the minimum number of pixels you need to toggle (after padding) in order for the image to be compressible for some k. More specifically, the steps are to first choose k, then the image is padded with zeros, then, we can toggle the pixels so it is compressible for this k. The image must be compressible in that state.
Input

The first line of input will contain two integers n, m (2 ≤ n, m ≤ 2 500), the dimensions of the image.

The next n lines of input will contain a binary string with exactly m characters, representing the image.
Output

Print a single integer, the minimum number of pixels needed to toggle to make the image compressible.

惊呆了 刚开始T在第三个样例 以为想法错了 后来把质数的预处理改大一点就过了 我也是惊呆了
因为 划分的小块k 一定是素数 2.3.5....因为不是素数的话可以划分为多个素数的和 结果还是一样的

然后预处理出质数 再用二维前缀和记录 (1,1)~(i,j)矩阵的和 详细看代码

 #include <cstdio>      #include <algorithm>      #include <iostream>      #include <cstring>      using namespace std;      const int MAX = 5005;      const int INF = 0x3f3f3f3f;      char a[2502][2502];      int b[MAX][MAX];      int sum[MAX][MAX];      bool not_primer[MAX];           int num[MAX];      int numb;      int main()      {          not_primer[1] = 1;          int k = 0;                                  //预处理出 2 ~ 2505 的质数放在num数组里          for(int i = 2; i <= 2505; i++) {              if(not_primer[i] == 0)                  num[k++] = i;                               for(int j = i*2; j <=2505; j+= i) {     // 把素数的倍数都标记为不是素数                 not_primer[j] = 1;           // 不是素数标记为 1            }          }          int n,m;          while(~scanf("%d%d",&n,&m)) {              int maxx = n>m?n:m;              getchar();              memset(b,0,sizeof(b));              for(int i = 1; i <= n; i++) {                  for(int j = 1; j <= m; j++) {                      scanf("%c",&a[i][j]);                      b[i][j] = a[i][j]-'0';                  }                  getchar();              }              for(int i = 1; i < MAX; i++) {                // 因为对不够的地方要补行和列 所有前缀和 要求的大一些                for(int j = 1; j < MAX; j++) {                      sum[i][j] = sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+b[i][j];          //二维前缀和处理 1~2*2500之间的矩阵和                  }              }              int ans = INF;              for(int i = 0; num[i] <= maxx; i++) {     // 以num[i] 为区间块进行分割                int s = num[i]*num[i];          //如果该区间全为1的话 前缀和是多少                  int x = num[i];                            int y = num[i];                  for(;;) {               // x ,y是以 num[i]为块对横纵补0 之后的 行数和列数                    if(x < n) {                          x += x;                      }                      if(y < m) {                          y += y;                      }                      if(x >= n && y >= m)                          break;                         }                  int ans1;                  int ans2 = 0;                  for(int j = num[i]; j <= x; j+=num[i]) {     // j表示 划分的方块的一条边                          int J = j-num[i]+1;                 // 划分的方块中与j对应的边                      for(int l = num[i]; l <= y; l += num[i]) {         //同上                            int L = l-num[i]+1;                             ans1 = sum[j][l]-sum[j][L-1]-sum[J-1][l]+sum[J-1][L-1];   // 容斥原理 求 矩阵(J,L) ~(j,l)的前缀和                           ans1 = min(ans1,s-ans1);                            //要么全部转换为1  要么全部转换为0 两种取最小                             ans2 += ans1;                                            }                  }                  ans = min(ans,ans2);              }              printf("%d\n",ans);          }      }  



原创粉丝点击