Codeforces Round #553 B. Dima and a Bad XOR

题面:

传送门

题目描述:

题意很简单:在一个N*M的矩阵中(N行M列),问是否可以:每行选一个整数,使他们的异或和大于0。如果不可以,输出"NIE";如果可以,输出"TAK",并输出选择的整数。

题目分析:

这道题刚开始想直接暴力,但看到复杂度竟然是O(500^500),就怂了??。到后面仔细观察,发现题目有个数据:每个数小于1024,也就是2^10次方。会不会跟数位有关?后面分析了一下,果然是,但没时间做了??,不过结束后还是A出来了。

异或(求大佬无视):转化为二进制后按位异或,相同位会变为0,不同位会变为1。比如3和5进行异或,3的二进制是11,5的二进制是101,结果就是110:

(注:上面最右边的第一位由于是相同位(1,1),所以变成了0,第二位是不同位,所以变成了1,第三位:因为11没有第三位,所以补一个0,变成011,然后再进行按位异或。结果就是110,然后110会转化位十进制,也就是最终结果是6,即3和5异或是6)

为什么要强调这个异或呢?其实重点不在于异或的规则,而在于异或转化为二进制处理的思想。我们把结果按照二进制来看:假如我们选出来的整数全部进行异或后,得到的结果转化位二进制,每个二进制位至少有一个不为0,就可以输出答案了。然后我们再看看题目数据限制:每个整数不超过1024,也就是说异或出来的结果也不超过1024,即结果的二进制位最多为9位。算下来时间复杂度是O(9*500*500),1e6左右,不会超时。所以,我们的核心思想就是:枚举结果的二进制位,尽量使结果中的二进制位含有1。剩下来就是贪心了。

我们再分析一下,会发现其实很容易得到这样的分类:假如当前是想让结果的第num个二进制位为1,那么,就会有:1.某一行的全部整数在第num个二进制位为1,2.某一行的全部整数在第num个二进制位为0,3.某一行的部分整数在第num个二进制位为1,另一部分在第num个二进制位为0。按照这三类,我们就可以分析这三类情况对 “异或后结果的第num个二进制位为1” 的贡献:首先,第二种情况没有任何贡献;其次,如果第一种情况是有奇数行,那么只需要使符合第三种情况的行选出来的整数在第num个二进制位为0,就可以让结果的第num个二进制位为1;如果第一种情况是有偶数行,那么只需要选出符合第三种情况的其中一行,使这一行选出的整数第num个二进制位为1,第三种情况剩下的行选出来的整数在第num个二进制位为0就行了。

AC代码(代码巨丑):

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 int n, m;
  7 int G[505][505];
  8 struct node{
  9     int odd, even;
 10     int is;
 11 };
 12 node row[505];
 13
 14 int main(){
 15     scanf("%d%d", &n, &m);
 16     for(int i = 0; i < n; i++){
 17         for(int j = 0; j < m; j++){
 18             scanf("%d", &G[i][j]);
 19         }
 20     }
 21
 22     int t;
 23     for(int num = 0; num <= 8; num++){  //枚举结果的位
 24         //分类
 25         for(int i = 0; i < n; i++){
 26             row[i].odd = 0, row[i].even = 0;
 27             for(int j = 0; j < m; j++){
 28                 t = (G[i][j] >> num);     //取出整数的第num位
 29                 if(t & 1) row[i].odd = 1;
 30                 else row[i].even = 1;
 31             }
 32             if(row[i].even == 1 && row[i].odd == 1){
 33                 row[i].is = 2;     //第三种情况
 34             }
 35             else if(row[i].even == 1){
 36                 row[i].is = 0;     //第一种情况
 37             }
 38             else row[i].is = 1;    //第二种情况
 39         }
 40
 41         int flag = 0;      //标记
 42         int cnt = 0;       //统计第一种情况个数
 43         for(int i = 0; i < n; i++){
 44             if(row[i].is == 1) cnt++;
 45         }
 46         if(cnt % 2 == 1) flag = 1;   //第一种情况为奇数个
 47
 48         for(int i = 0; i < n; i++){
 49             if(row[i].is == 2){      //有符合第三种情况的行,也必定可以产生贡献
 50                 flag = 1;
 51                 break;
 52             }
 53         }
 54
 55         if(flag) {
 56             printf("TAK\n");
 57             if(cnt % 2 == 1){
 58                 for(int i = 0; i < n; i++){
 59                     if(row[i].is == 2){
 60                         for(int j = 0; j < m; j++){
 61                             t = (G[i][j] >> num);
 62                             if(t % 2 == 0){
 63                                 printf("%d", j+1);
 64                                 break;
 65                             }
 66                         }
 67                     }
 68                     else printf("%d", 1);       //1是随便取的,只要在[1,m]内就行
 69
 70                     //输出格式
 71                     if(i == n-1) printf("\n");
 72                     else printf(" ");
 73                 }
 74             }
 75             else{
 76                 int fd = -1;
 77                 //随便找符合第三种情况的一行,产生贡献
 78                 for(int i = 0; i < n; i++){
 79                     if(row[i].is == 2) {
 80                         fd = i;
 81                         break;
 82                     }
 83                 }
 84
 85                 for(int i = 0; i < n; i++){
 86                     if(row[i].is == 2){
 87                         if(i == fd){
 88                             for(int j = 0; j < m; j++){
 89                                 t = (G[i][j] >> num);
 90                                 if(t % 2 == 1){
 91                                     printf("%d", j+1);
 92                                     break;
 93                                 }
 94                             }
 95                         }
 96                         else{
 97                             for(int j = 0; j < m; j++){
 98                                 t = (G[i][j] >> num);
 99                                 if(t % 2 == 0){
100                                     printf("%d", j+1);
101                                     break;
102                                 }
103                             }
104                         }
105                     }
106                     else printf("%d", 1);    //同上
107
108                     //输出格式
109                     if(i == n-1) printf("\n");
110                     else printf(" ");
111                 }
112             }
113             return 0;
114         }
115     }
116
117     printf("NIE\n");
118
119     return 0;
120 }

原文地址:https://www.cnblogs.com/happy-MEdge/p/10976368.html

时间: 2024-08-07 15:10:10

Codeforces Round #553 B. Dima and a Bad XOR的相关文章

Codeforces Round #553 (Div. 2) C题

题目网址:http://codeforces.com/contest/1151/problem/C 题目大意:给定奇数集和偶数集,现构造一个数组,先取奇数集中一个元素1,再取偶数集二个元素2,4,再取奇数集四个元素3,5,7,9,再取偶数集八个元素,6,8,10…… 得到 1,2,4,3,5,7,9,6,8,10,12……问这个数组的某一区间和是多少,并对1e9+7取模. 题解:对于奇数集x和偶数集y的前k项,有x=k^2,y=k*(k+1),首先,计算区间和,可以用前缀和,当计算前n项的和时,

Codeforces Round #553 (Div. 2) B题

题目网址:http://codeforces.com/contest/1151/problem/B 题目大意:给定一个n*m的矩阵,问是否可以从每一行中选择一个数,使得这n个数异或大于0,如果可以还要输出它们的列位置 题解:首先如果a^b==0,b!=c,则a^c>0.那么考虑构造,为了方便,选取第一列的数,如果异或>0,直接输出列位置,反之则随便在一行中,找到一个与第一个不相等的数,那么由异或性质满足条件,如果n行都找不到,则无法实现. 1 #include<bits/stdc++.h

Codeforces Round #262 (Div. 2) 460B. Little Dima and Equation(枚举)

题目链接:http://codeforces.com/problemset/problem/460/B B. Little Dima and Equation time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Little Dima misbehaved during a math lesson a lot and the nas

Codeforces Round #214 (Div. 2)——Dima and Salad

题目链接 题意: 一行a[i],一行b[i],a和b是一一对应的.选取任意个数对,使得sigma(a)/ sigma(b)等于k,求这时候sigma(a)的最大值 分析: 这个题目关键在于对sigma(a)/ sigma(b)== k的处理.对于这种式子,用每个数的比值显然是不行的,因为没法累加:而且是double型,没法DP 考虑一个每个数对对这个式子的影响,如果每个数都是a = k * b,那么显然是可以的:如果a小于k * b,那么在整体中,当前数对少的数肯定要有一些数对来补偿,也就是说,

Codeforces Round #262 (Div. 2) 总结:二分

B. Little Dima and Equation 思路:本来前两题都很快做出来的,然后觉得ranting应该可以增加了.然后觉得代码没问题了,又想到了一组cha人的数据,然后就锁了,然后刚锁就被别人cha了看了代码才发现尼玛忘了判断小于10^9了,然后C反正想了好多种方法都不会就没心情了,就这样rating又降了 #pragma comment(linker, "/STACK:1024000000,1024000000") #include<iostream> #in

Codeforces Round #262 (Div. 2) 题解

A. Vasya and Socks time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasya has n pairs of socks. In the morning of each day Vasya has to put on a pair of socks before he goes to school. When

Codeforces Round #262 (Div. 2) B

题目: B. Little Dima and Equation time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Little Dima misbehaved during a math lesson a lot and the nasty teacher Mr. Pickles gave him the following pr

Codeforces Round #260 (Div. 2) A. Laptops(简单题)

题目链接:http://codeforces.com/problemset/problem/456/A A. Laptops time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output One day Dima and Alex had an argument about the price and quality of laptops.

Codeforces Round #262 (Div. 2)解题报告

详见:http://robotcator.logdown.com/posts/221514-codeforces-round-262-div-2 1:A. Vasya and Socks   http://codeforces.com/contest/460/problem/A 有n双袜子,每天穿一双然后扔掉,每隔m天买一双新袜子,问最多少天后没有袜子穿.. 简单思维题:以前不注重这方面的训练,结果做了比较久,这种题自己边模拟边想.不过要多考虑trick ```c++ int main(){ i