codeforces838A Binary Blocks

                                                                                                                                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);  
        }  
    }  



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值