BestCoder Round #67 (div.2)总结

1001 N bulbs

 
 Accepts: 275
 
 Submissions: 1237
 Time Limit: 10000/5000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
N个灯泡从左到右排成一排,左边的是第一个,右边的最后一个,下标从1到n。有些开着,有些关着,为了节约用电,你要关上所有灯,但是你又很懒。
刚好有个熊孩纸路过,他刚好要从第一个灯泡走去最后一个灯泡,然后离开。
熊孩子从第一个灯泡出发,每次可以往左右两个相邻的灯泡走。
但是毕竟熊孩纸,熊孩纸在离开一个灯泡之前,一定会动一下当前这个灯泡的开关,也就是开的变关,关的变开。
想问你可不可能关完所有的灯,同时熊孩纸也可以到达最后一个灯泡,然后离开。
输入描述
第一行T,表示T组数据。
接下来T组数据:
每组数据,第一行N,后面一行一个01序列,表示灯泡的初始开关状态,0表示关,1表示开。
1\leq T \leq 101T10
1\leq N \leq 10000001N1000000
输出描述
每组数据,如果可以输出"YES",否则输出"NO"。
输入样例
1
5
1 0 0 0 0
输出样例
YES
Hint
孩子的路径是:123234545
刚好除了第一盏灯,其他灯都只经过偶数次。
官方题解:

我们注意到总的操作次数是跟nn奇偶的。这个很重要,也就是如果11的数量和nn不同奇偶,那么一定无解。

那么现在问题是11nn同奇偶的情况下,是不是一定有解?答案是显然的。

因为11nn同奇偶,所以00的个数是偶数,我们发现当我们从11走到ii时,假设我们往回走到左边某个点kk,再走回来ii,那么你会发现有且仅有kkii这两个数被设成没有操作。

也就是说我们可以每次任意选择两个点设成没有操作,然而不需操作的点数是偶数个,所以刚好可以满足。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxm=1e6+10;
int a[maxm];
int n;
int main()
{
    int t,i;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1; i<=n; i++)
        {
            scanf("%d",&a[i]);
            a[i] = (a[i]+1)%2 ;
        }
        for(i=1; i<n; i++)
        {
            if(a[i]==1)
            {
                a[i] = 0;
                a[i+1] = (a[i+1]+1)&1;
            }
        }
        if(a[n]==0)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}

1002 N*M bulbs

 
 Accepts: 94
 
 Submissions: 717
 Time Limit: 10000/5000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
N*M个灯泡排成一片,也就是排成一个N*M的矩形,有些开着,有些关着,为了节约用电,你要关上所有灯,但是你又很懒。
刚好有个熊孩纸路过,他刚好要从左上角的灯泡走去右下角的灯泡,然后离开。
但是毕竟熊孩纸,熊孩纸在离开一个灯泡之前,一定会动一下当前开关,也就是开的变关,关的变开。
想问你可不可能关完所有的灯,同时熊孩纸也可以到达右下角的灯泡,然后离开。
输入描述
第一行T,表示T组数据。
接下来T组数据:
每组数据,第一行N,M,后面一个N*M的01矩阵,表示灯泡的初始开关状态,0表示关,1表示开。

1 \leq T \leq 101T10
1 \leq N, M \leq 10001N,M1000
输出描述
每组数据,如果可以输出"YES",否则输出"NO"。
输入样例
1
1 5
1 0 0 0 0
输出样例
YES
Hint
孩子的路径是:123234545
刚好除了第一盏灯,其他灯都只经过偶数次。
官方题解:

我们发现操作数跟n+m-1n+m1同奇偶,那是不是当11的个数跟n+m-1n+m1同奇偶是就是YES呢?

答案是肯定的,我们这样看:首先将棋盘黑白染色,就是若(i,j)(i,j)格子,若(i+j)(i+j)是奇数,那么就是黑格子,否则就是白格子。

我们发现我们可以通过一种操作使得从一个格子走到斜方向的任意一个格子。

这个操作很简单,我们假设一个2*222的棋盘:

1 2

3 4

我们这样走:1->2->1->2->41>2>1>2>411就直接走到44了,而且不产生任何操作。

也就是同色格子可以互相到达。

然后我们发现如果要操作一个开关,那么最后所在格子颜色一定会改变。

同上面这个例子:

1 2

3 4

假设我们要操作22这个格子。

1->2->1->31>2>1>3

我们成功操作了22这个格子,但是从白格子转到黑格子了。

也就是说

假设格子(n,m)(n,m)下面有个格子(n+1,m)(n+1,m)是最后终点,然而每次操作一个格子需要改变一次颜色。

也就是我们从(1,1)(1,1)改变了若干次颜色后,最后颜色一定要和(n+1,m)(n+1,m)相同。

也就是说11的个数要和(n+1+m)(n+1+m)同奇偶。

也就是说11的个数要和(n+m-1)(n+m1)同奇偶。

否则无解。

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxm=1e3+10;
int a[maxm][maxm];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m,n;
        scanf("%d%d",&m,&n);
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                scanf("%d",&a[i][j]);
                cnt+=a[i][j];
            }
        }
        if(cnt%2==(m+n-1)%2)
        {
            printf("YES\n");
        }
        else
        {
            printf("NO\n");
        }
    }
    return 0;
}



你可能感兴趣的:(BestCoder Round #67 (div.2)总结)