hdu 4592 Boring Game

Boring Game

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)

Total Submission(s): 544    Accepted Submission(s): 91

Problem Description

Zero likes to play a boring game when he feels extremely boring. This his game proceeds in a square board with n rows and n column. Each grid in the board has either of two colors black or white. In each turn, Zero chooses a grid first. Let’s assume that the
grid he chooses locates in the xth row and the yth column. And then, the neighbors which are existed of this grid (x + 1, y), (x – 1, y), (x, y + 1), (x, y – 1) and itself will convert their color into another. Till the end, Zero will
transform the initial board to the goal board whose grids are all white. For instance, Here is the way to attain his goal. In his first turn, he selects (2, 2). And then he selects (1, 1) in the second turn. After that, he reaches his goal.

Zero reckons this mission, however, is too simple and naive. So he prefers to accomplish this assignment in minimal turns. He doesn’t know whether the turns he needs are the minimal turns, because of that he needs you to tell him the minimal turns of these
initial boards.

Input

There are several test cases in the input file. The first line of the input file contains an integer m(m <= 106), then m cases follow.

The first line of each test case contains an integer n(1 <= n <= 8), which is the length of a side of the square board.

Then the next line contains n integer a[i](0 <= a[i] <= 2n, 1 <= i <= n), which is the statement of the ith row respectively. The definition of a statement can be illustrated as n-length binary numbers, zero represents white and one represents
black. For example, when n is equal to 4 and a[0] is equal to 5 = (0101)2, you can consider that the condition in the first line of this board is white, black, white, black.

Output

For each test case, output the minimal turns. If the initial board doesn’t contain a way to reach the goal board, please output -1.

Sample Input

2
3
4 3 2
4
1 0 0 0

Sample Output

2
-1

Source

2013
ACM-ICPC南京赛区全国邀请赛——题目重现

题解及代码:

这道题的意思很简单,但是数据量巨大,而且卡时间卡的比较紧,这样我们可以进行一下预处理。我们将n=1---8高消之后的矩阵求出来可以看到:4和5是多解的情况,而其他的都是唯一解。那么我们就可以把其他情况的系数矩阵的逆矩阵求出来,直接打表放在代码中,当我们输入增广矩阵的最后一列的时候,就直接与逆矩阵直接相乘就能得到最后结果;对于4和5,我们就直接用高消求就可以了。

按照这种方法,只能运行到将近95W组数据,所以还需要处理一下:我们已经将逆矩阵求出来了,每一位不是0就是1,整个矩阵还是比较大,枚举的话还是会超时,所以我们将每n位换算成一个10进制数,矩阵相乘时,直接异或就可以了,最后求一下每个x[i]中1的个数就可以了,这样能节省很多时间。

看了看ac的名单,感觉这思路还不是很好,代码量巨大,而且速度也不快,如果读者有更好的方法,希望能留言,探讨一下这道题,感谢!

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;

int A2[4][2]=
{
    {3,2},{3,1},
    {2,3},{1,3}
};

int A3[9][3]=
{
    {5,1,6},{0,2,7},{5,4,3},
    {1,3,1},{2,7,2},{4,6,4},
    {6,1,5},{7,2,0},{3,4,5}
};

int A6[36][6]=
{
    {43,8,55,10,44,40},{3,20,53,17,14,4},{44,42,7,32,55,34},{13,21,56,1,59,17},{48,10,43,34,28,8},{53,4,59,20,13,5},
    {8,28,2,27,34,44},{20,54,5,59,21,14},{42,43,10,48,2,55},{21,53,20,3,16,59},{10,27,40,55,42,28},{4,14,16,54,17,13},
    {55,2,48,42,27,10},{53,5,56,1,59,17},{7,10,28,40,48,32},{56,20,14,5,3,1},{43,40,7,32,55,34},{59,16,3,21,54,20},
    {10,27,42,48,2,55},{17,59,1,56,5,53},{32,48,40,28,10,7},{1,3,5,14,20,56},{34,55,32,7,40,43},{20,54,21,3,16,59},
    {44,34,27,2,28,8},{14,21,59,5,54,20},{55,2,48,10,43,42},{59,16,3,20,53,21},{28,42,55,40,27,10},{13,17,54,16,14,4},
    {40,44,10,55,8,43},{4,14,17,53,20,3},{34,55,32,7,42,44},{17,59,1,56,21,13},{8,28,34,43,10,48},{5,13,20,59,4,53}
};

int A7[49][7]=
{
    {109,65,14,84,88,16,96},{108,34,27,2,28,40,112},{3,20,53,81,110,84,56},{107,0,107,8,119,42,28},{96,20,86,69,59,21,14},
    {27,34,108,32,28,10,7},{91,65,56,21,13,4,3},{65,99,21,86,68,56,16},{34,119,32,7,42,108,40},{20,54,69,91,5,86,84},
    {0,0,8,28,34,107,42},{20,54,81,109,80,53,21},{34,119,2,112,42,27,10},{65,99,84,53,17,14,4},{14,21,59,5,54,68,88},
    {27,32,107,8,119,42,28},{53,69,88,17,99,5,110},{107,8,119,34,0,34,119},{86,81,13,68,99,80,59},{108,2,107,8,119,42,28},
    {56,84,110,80,54,17,13},{84,86,5,91,5,86,84},{2,7,8,27,8,7,2},{81,91,17,96,17,91,81},{8,28,34,107,34,28,8},
    {69,109,68,3,68,109,69},{32,112,8,108,8,112,32},{21,53,80,109,80,53,21},{88,68,54,5,59,21,14},{28,42,119,8,107,32,27},
    {110,5,99,17,88,69,53},{119,34,0,34,119,8,107},{59,80,99,68,13,81,86},{28,42,119,8,107,2,108},{13,17,54,80,110,84,56},
    {16,56,68,86,21,99,65},{40,108,42,7,32,119,34},{84,86,5,91,69,54,20},{42,107,34,28,8,0,0},{21,53,80,109,81,54,20},
    {10,27,42,112,2,119,34},{4,14,17,53,84,99,65},{96,16,88,84,14,65,109},{112,40,28,2,27,34,108},{56,84,110,81,53,20,3},
    {28,42,119,8,107,0,107},{14,21,59,69,86,20,96},{7,10,28,32,108,34,27},{3,4,13,21,56,65,91}
};

int A8[64][8]=
{
    {220,138,7,128,199,170,108,40},{214,81,13,64,237,1,238,68},{27,0,27,32,107,168,199,130},{237,81,54,16,14,5,3,1},
    {183,138,108,8,112,160,192,128},{216,0,216,4,214,21,227,65},{107,138,176,2,183,128,119,34},{59,81,224,1,227,85,54,20},
    {138,219,10,192,42,171,130,108},{81,219,17,224,65,3,69,238},{0,0,32,112,136,172,42,199},{81,219,65,56,21,13,4,3},
    {138,219,130,28,168,176,32,192},{0,0,4,14,17,53,84,227},{138,219,136,7,130,192,162,119},{81,219,80,3,84,213,65,54},
    {7,10,28,160,172,2,171,170},{13,17,54,16,14,5,3,1},{27,32,107,136,183,10,172,168},{54,65,213,68,59,20,13,5},
    {108,130,171,34,220,40,176,160},{216,4,214,17,237,80,53,21},{176,136,108,8,112,160,192,128},{224,80,56,5,53,64,213,85},
    {128,192,160,112,136,172,42,199},{64,224,16,216,84,14,65,237},{32,112,136,172,10,183,136,107},{16,56,68,214,69,59,21,14},
    {8,28,34,107,162,220,168,112},{4,14,17,53,80,237,17,214},{2,7,8,27,42,112,130,183},{1,3,5,14,17,53,84,227},
    {199,42,172,136,112,160,192,128},{237,65,14,84,216,16,224,64},{107,136,183,10,172,136,112,32},{14,21,59,69,214,68,56,16},
    {112,168,220,162,107,34,28,8},{214,17,237,80,53,17,14,4},{183,130,112,42,27,8,7,2},{227,84,53,17,14,5,3,1},
    {170,171,2,172,160,28,10,7},{1,3,5,14,16,54,17,13},{168,172,10,183,136,107,32,27},{5,13,20,59,68,213,65,54},
    {160,176,40,220,34,171,130,108},{21,53,80,237,17,214,4,216},{128,192,160,112,8,108,136,176},{85,213,64,53,5,56,80,224},
    {108,130,171,42,192,10,219,138},{238,69,3,65,224,17,219,81},{199,42,172,136,112,32,0,0},{3,4,13,21,56,65,219,81},
    {192,32,176,168,28,130,219,138},{227,84,53,17,14,4,0,0},{119,162,192,130,7,136,219,138},{54,65,213,84,3,80,219,81},
    {40,108,170,199,128,7,138,220},{68,238,1,237,64,13,81,214},{130,199,168,107,32,27,0,27},{1,3,5,14,16,54,81,237},
    {128,192,160,112,8,108,138,183},{65,227,21,214,4,216,0,216},{34,119,128,183,2,176,138,107},{20,54,85,227,1,224,81,59}
};

int a[30][30],x[80];//系数矩阵,解数组
int equ,var;//方程数,变元数

int Gauss()
{
    int k,col,max_r;

    for(k=0,col=0; k<equ&&col<var; k++,col++)
    {
        if(a[k][col]==0)
        {
            max_r=k;
            for(int i=k+1; i<equ; i++)
                if(a[i][col]>a[max_r][col])
                {
                    max_r=i;
                    break;
                }
            if(max_r!=k)
                for(int i=0; i<=var; i++)
                    swap(a[max_r][i],a[k][i]);
        }
        if(a[k][col]==0)
        {
            k--;
            continue;
        }
        for(int i=k+1; i<equ; i++)
        {
            if(a[i][col])
                for(int j=col; j<=var; j++)
                    a[i][j]=a[i][j]^a[k][j];
        }
    }
    for(int i=k; i<equ; i++)
        if(a[i][var]) return -1;

    int lim=(1<<(var-k)),ans=100000;
    for(int i=0; i<lim; i++)
    {
        int temp=i,sum=0;
        for(int j=var-1; j>=k; j--)
        {
            x[j]=temp&1;
            temp>>=1;
        }
        for(int j=k-1; j>=0; j--)
        {
            x[j]=a[j][var]&1;
            for(int r=j+1; r<var; r++)
                x[j]=x[j]^(a[j][r]&x[r]);
        }
        for(int j=0; j<var; j++)
            sum+=x[j];
        ans=min(ans,sum);
    }
    return ans;
}
void init(int n)
{
    equ=n*n;
    var=equ;
    memset(a,0,sizeof(a));
    memset(x,0,sizeof(x[0])*30);
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
        {
            if(i!=0) a[i*n+j][(i-1)*n+j]=1;
            if(i!=n-1) a[i*n+j][(i+1)*n+j]=1;
            if(j!=0) a[i*n+j][i*n+j-1]=1;
            if(j!=n-1) a[i*n+j][i*n+j+1]=1;
            a[i*n+j][i*n+j]=1;
        }
}

int main()
{
    int cas,n,X;
    scanf("%d",&cas);
    while(cas--)
    {
        scanf("%d",&n);
        if(n==1)
        {
            scanf("%d",&X);
            printf("%d\n",X);
            continue;
        }
        if(n==4||n==5)
        {
            init(n);
            for(int i=0; i<n; i++)
            {
                scanf("%d",&X);
                int r=(i+1)*n-1,l=i*n;
                while(r>=l)
                {
                    a[r][var]=X&1;
                    X>>=1;
                    r--;
                }
            }
            int ans=Gauss();
            printf("%d\n",ans);
            continue;
        }

        int ans=0;
        int t[80];
        for(int i=0; i<n; i++)
        {
            scanf("%d",&t[i]);
        }
        equ=n*n;
        memset(x,0,sizeof(x[0])*(equ+4));
        if(n==2)
        {
            for(int j=0; j<n; j++)
                if(t[j])
                {
                    for(int i=0; i<equ; i++)
                    {
                        x[i]=x[i]^(A2[i][j]&t[j]);
                    }
                }
        }
        else if(n==3)
        {
            for(int j=0; j<n; j++)
                if(t[j])
                {
                    for(int i=0; i<equ; i++)
                    {
                        x[i]=x[i]^(A3[i][j]&t[j]);
                    }
                }
        }
        else if(n==6)
        {
            for(int j=0; j<n; j++)
                if(t[j])
                {
                    for(int i=0; i<equ; i++)
                    {
                        x[i]=x[i]^(A6[i][j]&t[j]);
                    }
                }
        }
        else if(n==7)
        {
            for(int j=0; j<n; j++)
                if(t[j])
                {
                    for(int i=0; i<equ; i++)
                    {
                        x[i]=x[i]^(A7[i][j]&t[j]);
                    }
                }
        }
        else if(n==8)
        {
            for(int j=0; j<n; j++)
                if(t[j])
                {
                    for(int i=0; i<equ; i++)
                    {
                        x[i]=x[i]^(A8[i][j]&t[j]);
                    }
                }
        }
        for(int i=0; i<equ; i++)
        {
            int t=0;
            while(x[i])
            {
                t^=(x[i]&1);
                x[i]>>=1;
            }
            ans+=t;
        }
        printf("%d\n",ans);
    }
    return 0;
}
时间: 2024-10-08 16:58:22

hdu 4592 Boring Game的相关文章

HDU 5008 Boring String Problem(西安网络赛B题)

HDU 5008 Boring String Problem 题目链接 思路:构造后缀数组,利用height的数组能预处理出每个字典序开始的前缀和有多少个(其实就是为了去除重复串),然后每次二分查找相应位置,然后在往前往后找一下sa[i]最小的 代码: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int

HDU - 4961 Boring Sum

Problem Description Number theory is interesting, while this problem is boring. Here is the problem. Given an integer sequence a1, a2, -, an, let S(i) = {j|1<=j<i, and aj is a multiple of ai}. If S(i) is not empty, let f(i) be the maximum integer in

hdu 4961 Boring Sum(高效)

题目链接:hdu 4961 Boring Sum 题目大意:给定ai数组; 构造bi, k=max(j|0<j<i,aj%ai=0), bi=ak; 构造ci, k=min(j|i<j≤n,aj%ai=0), ci=ak; 求∑i=1nbi?ci 解题思路:因为ai≤105,所以预先处理好每个数的因子,然后在处理bi,ci数组的时候,每次遍历一个数,就将其所有的因子更新,对于bi维护最大值,对于ci维护最小值. #include <cstdio> #include <c

HDU 4961 Boring Sum 暴力

题意:对于所有的A[I],同时找到左边和右边离它最近且是它的倍数的数相乘最后加起来求和. 解题思路:n*sqrt(n)的算法,开始以为过不了,wa了两发因为lld I64d对拍一个小时发现一个小时前交的代码没错只是没变I64d,..具体思路是枚举每个a[i]的因子,找离它最近的那个更新,如果已经没更新就不用更新了.用两个辅助数组记录最近的就行. 解题代码: 1 // File Name: 1002.cpp 2 // Author: darkdream 3 // Created Time: 201

HDU 4961 Boring Sum 构造题

用一个数组c, c[i]表示i这个数出现的最近数字是几. 那么当加入一个6,则 c[1] = c[2] = c[3] = c[6] = 6; ==最近怎么都要开挂啊.. #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int N = 100005; inl

hdu 5008 Boring String Problem(后缀数组)

题目链接:hdu 5008 Boring String Problem 题目大意:给定一个字符串,初始状态l,r为0,每次询问子串中字典序第l^r^v+1的子串区间,对于重复的输出下标小的. 解题思路:后缀数组,对给定字符串做后缀数组,然后根据height数组确定每个位置做为起点的子串有多少,然后二分查找确定起点位置,但是因为子串的重复的要输出下表小的,所以确定起点后还要确定字典序最小的下标. #include <cstdio> #include <cstring> #includ

hdu 3518 Boring counting(后缀数组)

Boring counting                                                                       Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Problem Description 035 now faced a tough problem,his english teacher gives him

hdu 5008 Boring String Problem(后缀自动机构造后缀树)

hdu 5008 Boring String Problem(后缀自动机构造后缀树) 题意:给出一个字符串s,然后每次询问一个k,求s的所有子串中,字典序第k小的是谁?多个解,则输出最左边的那个 解题思路:这道题应该是为后缀树量身定制的吧.只要构造出了后缀树,然后按字典序遍历就可以得出每个节点包含的子串的字典序的范围了,而且必然是个连续的区间范围.但是我不会后缀树啊..比赛的时候突然想到,后缀自动机是可以构造后缀树的,虽然以前没写过,但还是硬着头皮上吧,居然还真的让我给撸出来了.我的做法是这样的

HDU 4961 Boring Sum 打表、更新

点击打开链接 Boring Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 715    Accepted Submission(s): 351 Problem Description Number theory is interesting, while this problem is boring. Here is th