第一行为绘制这幅画需要的颜色种数n (1 ≤ n ≤ 50) 第二行为n个数xi(1 ≤ xi ≤ 1,000,000,000),表示需要的各种颜料.
输出最少需要在商店购买的颜料颜色种数,注意可能购买的颜色不一定会使用在画中,只是为了产生新的颜色。
3 1 7 3
3
//// main.cpp
// NiuKe_HunHeYanLiao
//
// Created by 麦心 on 16/8/18.
// Copyright © 2016 年 程序工匠 0_0 小姐 . All rights reserved.
//
#include <iostream>
using namespace std ;
#include <vector>
#include <algorithm>
// 求一个数的二进制的最高位是哪位
int getHighBit( int num){
int highbit = 0 ;
while (num) {
// 将该数的二进制右移一位
num>>= 1 ;
highbit++;
}
return highbit;
}
int main() {
vector < int > colors;
int n;
while ( cin >> n){
colors. clear ();
int result = 0 ;
int temp;
int i = n;
while (i--) {
cin >>temp;
colors. push_back (temp);
}
// 将 colors 进行从小到大的排序
sort (colors. begin (), colors. end ());
int bigger, smaller;
//bigger 和 smaller 始终指向的是最后一位和倒数第二位数
bigger = n - 1 ;
smaller = bigger - 1 ;
while (colors. size ()> 2 ) {
// 如果两者的最高位相同,说明最高位可以消掉,
// 将两者 xor ,或者说将矩阵两行相减消掉最高位
if ( getHighBit (colors[ bigger ]) == getHighBit (colors[ smaller ])){
int tem = colors[ bigger ]^colors[ smaller ];
//find 函数头文件是 <algorithm>
// 泛型算法的 find ,在非 string 类型的容器里,可以直接找出所对应的元素
// 从 vector 的头开始一直到尾,找到第一个值为 temp 的元素,返回的是一个指向该元素的迭代器 std::vector<int>::iterator 类型
// 因为现在 xor 的是两个最大的数,而且最高位已被消掉,所以 xor 得到的结果一定比这两个数小
// 如果 temp 这个 比最大两个数小的 数没有被找到,则将 temp 加到 colors 数组中,进行再次 xor
// 找不到的话,返回 colors.end 应该是固定用法
if ( find (colors. begin (), colors. end (), tem)==colors. end ()){
colors. push_back (tem);
sort (colors. begin (), colors. end ());
bigger++; // 因为 colors 中多了一个数,所以需要位数+ 1
smaller++;
}
} else {
result++;
}
// 如果两者最高位不同,说明已经所有数的最高位已经只有最大的那个数是 1 了,这样它已经不可能被消掉了,结果+ 1
// 如果两个最大数的最高位可以消掉,那么消除之后,最大数已被消掉,没有用了
// 如果两个最大数的最高位不可以消掉,那么结果+ 1 ,最大数也没有用了。
// 弹出最大数
colors. pop_back ();
// 因为弹出了一个数,所以 bigger 和 smaller 都要相应- 1
bigger = smaller;
smaller--;
}
cout <<result+2 << endl ;
}
}
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <vector> #include <algorithm> #include <stdio.h> using namespace std; //求该数最高位是第几位 int getHighPosition(int a){ int count = 0; while (a){ a >>= 1; count++; } return count; } int main(){ int n; vector<int> colors; while (cin>>n) { int temp; int res=0; int i = n; colors.clear(); while (i--){ cin >> temp; colors.push_back(temp); } sort(colors.begin(), colors.end()); //endValue和cmpValue指向最后一个数和倒数第二个数 int endValue = n-1; int cmpValue = endValue - 1; //两种颜色以上才有混合的可能,如果只需要两种颜色,那么最少就要购买两种,购买一种是不可能得到两种颜色的。 while (colors.size()>2) { //只有最高位相同,那么他们的最高位一定可以消去 if (getHighPosition(colors[endValue]) == getHighPosition(colors[cmpValue])) { int temp = colors[endValue] ^ colors[cmpValue]; //如果异或出来的这个低维的颜色没有,就加入到colors里 if (find(colors.begin(), colors.end(), temp) == colors.end()) { colors.push_back(temp); sort(colors.begin(), colors.end()); //因为新加入了一个数,所以为了让endValue和cmpValue还是指向倒数第一和倒数第二个数,需要++ endValue++; cmpValue++; } } else { res++; } //每判断完一次,就把最后一个数扔掉,没什么用了 colors.pop_back(); endValue = cmpValue; cmpValue--; } cout << res + colors.size() << endl; } }
''' 说明:以下代码和思路均是参考各位大神, 本人只做了额外的总结和解释,帮助大家理解。 问题理解: 输入n个数,将这些数之间进行多次xor(异或操作), 其中一个数可能被xor多次,看最后能剩余多少不重复的数,输出数量即可。 思路: 类似矩阵求秩:首先将各数从大到小排序, 对位数与该行相同的进行异或操作,操作结束后该行就“独立”了。 具体过程如下: 排序 i=0 异或 排序 i=1 异或 101010 --> 111010 --> 111010 --> 111010 --> 111010 --> 110110 --> 001100 --> 010111 --> 101101 --> 101101 --> 010111 --> 010000 --> 110110 --> 101010 --> 010000 --> 001100 --> 排序 i=2 排序 i=3 排序 i=4 end 111010 --> 111010 --> 111010 --> 111010 010111 --> 010111 --> 010111 --> 010111 000111 --> 001100 --> 001100 --> 001100 001100 --> 000111 --> 000111 --> 000111 ''' # 求数字转化为2进制后的位数 def getHiBit(n): ans = 0 while n: ans += 1 n >>= 1 return ans n = int(input()) colors = list(map(int, input().split())) colors.sort(reverse=True) # 从大到小排序 i = 0 while i<n and colors[i]: hibit = getHiBit(colors[i]) for j in range(i+1, n): if getHiBit(colors[j])==hibit: colors[j] ^= colors[i] else: break colors.sort(reverse=True) i += 1 print(i)
def getHiBit(n): ans = 0 while n: ans += 1 n >>= 1 return ans n = int(input()) colors = list(map(int, input().split())) colors.sort(reverse=True) i = 0 while i<n and colors[i]: hibit = getHiBit(colors[i]) for j in range(i+1, n): if getHiBit(colors[j])==hibit: colors[j] ^= colors[i] else: break colors.sort(reverse=True) i += 1 print(i)
#include<iostream> #include<string> #include<vector> #include<algorithm> using namespace std; int GetBitLength(int k){ int j = 0; while(k > 0){ k >>= 1; ++j; } return j; } int main(){ int i, j, n; cin>>n; vector<int> v(n); for(i = 0; i < n; ++i){ cin>>v[i]; } sort(v.begin(), v.end()); int res = 0; while(v.size() > 1){ vector<int> xor_num; j = v.size() - 1; while(j > 0 && GetBitLength(v[j]) == GetBitLength(v[j - 1])){ int xor_val = v[j] ^ v[j - 1]; if(xor_val != 0 && find(v.begin(), v.end(), xor_val) == v.end()){ xor_num.push_back(xor_val); } v.pop_back(); --j; } ++res; v.pop_back(); if(xor_num.size() > 0){ v.insert(v.end(), xor_num.begin(), xor_num.end()); sort(v.begin(), v.end()); } } cout<<res + v.size()<<endl; return 0; }
import java.util.*; import java.io.*; public class Main { /** *矩阵论中的知识表明,最大线性无关组是解的最基本的形式。 *这个题目类似于求矩阵的最大线性无关组,用高斯消元法就可以了,正向算一遍即可,反向不用计算(我们只关心无关组的向量个数,不关心具体解的形式)。 *多元方程,我们从左到右不为零开始消元,对于二进制数,那就是从大的数开始就可以了。 *用一个函数判断每一位是否为零,为零才消元。遍历的时候注意方程有几个,我们每次遍历的目标是消灭一列的1,使每一列最多1个一, *但是方程不够的时候,就不必向下消了,已经可以结束了。 */ public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine().trim()); int[] arrColor = new int[n]; String[] arrInput = br.readLine().trim().split(" "); for (int i=0; i<n; i++) { arrColor[i] = Integer.parseInt(arrInput[i]); } Arrays.sort(arrColor);//排序 int computLoopCnt = 0;//记录循环的个数 for (int i=31; i>=0; i--) {//遍历每一位,最大的数的该位为零就跳过 int row = (n - 1) - computLoopCnt; if (row <= 0) {//如果行数不够了,直接停止 break; } if (isNbitIsOne(arrColor[row],i)) {//判断该为是否为零 computLoopCnt++; for (int j=row-1; j>=0; j--) { if (isNbitIsOne(arrColor[j],i)) { arrColor[j] = arrColor[row] ^ arrColor[j]; } } Arrays.sort(arrColor, 0, row );//每次计算后排序,因为异或后可能变大,要正确找到最大的 } } int baseNum = 0; for (int i=0; i<n; i++) { if (arrColor[i] != 0) { baseNum++; } } System.out.println(baseNum); } public static boolean isNbitIsOne(int a, int n) {//判断第n位(顺寻方向:自右向左)是否为零 if (n > 32) { throw new IllegalArgumentException(); } int test = 1 << n; boolean isOne = false; if (test == (a & test)) { isOne = true; } return isOne; } }
#include<bits/stdc++.h> #define MAX 100 using namespace std; /* 大体思路是高斯消元法,数学背景就是XOR运算刚好是GF(2)上的加法,而所有的unsigned int刚好构成了GF(2)上32位的向量空间(本题只需30位)。 我们要求的值,也就是颜色向量组的秩。求秩的一个基本思路是高斯消元法化成行标准形矩阵。由于GF(2)是一个域,矩阵也是定义在域上的矩阵,可以加减乘除。 findFirstOne找到该数中非0的最高位,eg:findFirstOne(3)=2,findFirstOne(6)=3 findFirstOne(7)=3,仔细想想这就有点像线性代数里面找每行的第一个非0元。 getMax很好看懂,如果a>=b,显然findFirstOne(a)>=findFirstOne(b),如果a>b,findFirstOne(a)也是大于等于findFirstOne(b),未必严格大于。 我们先找第一个findFirstOne()最大的数,将它调到第一行,用异或操作消去该列的第一个非零元,然后指针指向第二个数,找第二个数到最后一个数中findFirstOne() 最大的数,将它调到第二行,以此类推。 for examle,输入: 3 1 2 3 算法先将3和1交换 3 2 1 3要和2异或,但不能和1异或(if(findFirstOne(arr[scan]) == firstone)这个判断),因为1的第二位本来就是0 变成 3 1 1 然后把3固定下来,指针指向2,变成3 1 0 我们发现秩为2,就是cur-1,这个很好理解。本代码所有变量均使用unsigned,数组从1开始。对了,对于例子中的输入对应的二进制矩阵Binary是 0 1 1 0 1 0 0 0 1 rank(Binary) = 2 */ unsigned findFirstOne(unsigned color) { //cout<<(mask>1000000000)<<endl; unsigned cnt = 30,mask=0x20000000;//这个数字刚好是一个30位的二进制数,比1000000000稍大一些。 while(mask) { if((mask&color)>0)//需要注意位运算优先级 return cnt; else { mask = mask>>1; cnt--; } } return 0; } unsigned getMax(unsigned arr[],unsigned start,unsigned length) { /* arr:一个unsigned数组,从1开始 start:开始扫描的位置 length:这个数组的长度 返回:这个数组元素最大值对应的下标 */ unsigned cnt; unsigned maxunsign = 0,argmax = start; for(cnt = start;cnt<=length;++cnt) { if(arr[cnt] > maxunsign) { maxunsign = arr[cnt]; argmax = cnt; } } if(maxunsign == 0)//已经全0,行标准型已经完成 return 0; else return argmax; } int main() { unsigned n,cur=1,arr[MAX],input,scan; unsigned ret,firstone; scanf("%u",&n);getchar();//使用getchar吸收换行符 input = n; while(input--) cin>>arr[n-input];//从1开始输入 for(cur = 1;cur<=n;++cur) { //依次扫描各行 ret = getMax(arr,cur,n); if(!ret) break; else if(ret!=cur) swap(arr[cur],arr[ret]); firstone = findFirstOne(arr[cur]);//反复用到,先记下来 for(scan = cur+1;scan<=n;++scan) { //行标准型要求每行首个非零元所在的列除了这个非零元以外全为0 if(findFirstOne(arr[scan]) == firstone) arr[scan] = arr[cur] ^ arr[scan]; } } cout<<cur-1<<endl; return 0; }
#include <iostream> #include <algorithm> using namespace std; int main() { int n,a[51]; cin>>n; for(int i=0;i<n;i++) cin>>a[i]; for(int i=n-1;i>0;i--) { sort(a,a+i+1); for(int j=i-1;j>=0;j--) { if((a[j]^a[i]) < a[j]) a[j] ^= a[i]; } } int k; for(k=0;a[k]==0;k++); cout<<n-k<<endl; return 0; }
#include<stdio.h> #include<algorithm> using namespace std; int a[50][32],equ,var=32; int solve(){ int res=0,c,j,i,k; for(c=0;c<var&&res<equ;c++,res++){ for(i=res;i<equ;i++) if(a[i][c]) break; if(equ==i) res--; else{ for(k=0;k<var;k++) swap(a[res][k],a[i][k]); for(k=i+1;k<equ;k++) if(a[k][c]) for(j=c;j<var;j++) a[k][j]^=a[res][j]; } } return res; } int main(){ int i,tmp; for(scanf("%d",&equ),i=0;i<equ;i++){ scanf("%d",&tmp); int index=31; while(tmp) a[i][index--]=tmp%2,tmp/=2; } printf("%d\n",solve()); }//求出矩阵的秩就可以了
// 从大到小遍历数组,当前元素与仅次于当前元素大小的元素如果长度相同, 异或之后消除第二个元素的最高位上的1,并把异或的结果复制给第二个元素, 每一个有1的位只留一个元素就够了。最后不是0的元素就是需要的原料。
/** * Created by hudaoyun on 16/8/24. *参考一楼的答案,求矩阵的秩 */ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Scanner; public class Main { public static void main(String[] args){ Scanner in = new Scanner(System.in); int n = in.nextInt(); ArrayList<Integer> colors = new ArrayList<Integer>(); for (int i = 0; i < n; i++){ int x = in.nextInt(); colors.add(x); } Collections.sort(colors); int bigest = n-1; int bigsecond = bigest - 1; int result = 0; while(colors.size() > 2){ if (getHighPosition(colors.get(bigest)) == getHighPosition(colors.get(bigsecond))){ int temp = colors.get(bigest) ^ colors.get(bigsecond); if (!colors.contains(temp)){ colors.add(temp); Collections.sort(colors); bigest = colors.size() - 1; bigsecond = bigest - 1; } }else{ result++; } colors.remove(colors.size() - 1); bigest = bigsecond; bigsecond--; } System.out.println(result + 2); } public static int getHighPosition(int a){ int count = 0; while(a > 0){ count++; a = a >> 1; } return count; } }
/*参考loolroco写出来的代码*/ #include<iostream> #include<map> #include<vector> #include<set> #include<math.h> #include<algorithm> using namespace std; int highPostion(int a){ int res = 0; while (a){ a >>= 1; res++; } return res; } int main(){ int n; while (cin >> n){ int res = 0; set<int> s; for (int i = 0; i<n; i++){ int tmp; cin >> tmp; s.insert(tmp); } set<int>::reverse_iterator r = ++s.rbegin(); int esVal, endVal; while (s.size()>2){ esVal = *r--; endVal = *r; while (highPostion(endVal) == highPostion(esVal) && s.size() >= 2){ int tmp = esVal ^ endVal; if (s.find(tmp) == s.end()){ s.insert(tmp); } s.erase(endVal); r = ++s.rbegin(); esVal = *r--; endVal = *r; } res++; s.erase(endVal); r = ++s.rbegin(); } cout << res + s.size() << endl; } return 0; }
#include <iostream> #include <vector> using namespace std; int main(){ int cnt = 29; cin >> cnt; vector<int> nums(cnt); for(int i=0; i<cnt; ++i){ cin >> nums[i]; } vector<bool> mask(cnt, false); int mask_bits = 0x01; for(int i=0; i<32; ++i){ int cur = 0; for(cur=0; cur<cnt; ++cur){ // find one number as base if(mask[cur] == false && ((nums[cur]&mask_bits) > 0) ) { mask[cur] = true; break; } } // then xor the found base to all other nonmask number for(int j=cur+1; j<cnt; ++j){ if( (nums[j]&mask_bits) > 0 ){ nums[j] ^= nums[cur]; } } mask_bits = mask_bits << 1; } // count the base number cnt = 0; for( int i=0; i<nums.size(); ++i){ if(mask[i] == true){ ++cnt; } } cout << cnt << endl; return 0; }
#include <iostream> #include <algorithm> using namespace std; int main() { int i,j,n,x[55]; cin>>n; for(i=0;i<n;++i) cin>>x[i]; for(i=n-1;i>0;--i) { sort(x,x+i+1); for(j=i-1;j>=0;--j) if((x[i]^x[j])<x[j]) x[j]^=x[i]; } for(i=0;x[i]==0;++i); cout<<n-i; return 0; }
//数组从小到大排列,从最下面一行开始,每次消去最高位的1,比如A行的系数减去B行,直接A = A^B就行 import java.util.*; public class hunheyanliao { public static void main(String[] args) { Scanner scan = new Scanner(System.in); while(scan.hasNext()){ int n = scan.nextInt(); int[] col = new int[n]; for(int i=0; i<n; i++){ col[i] = scan.nextInt(); } Arrays.sort(col); int count = 0; for(int i=n-1; i>=0; i--){ for(int j=i-1; j>=0; j--){ if(highbit(col[i]) == highbit(col[j])){ col[j] = col[j] ^ col[i]; } } Arrays.sort(col); } for(int i=0 ;i<n;i++) if(col[i] !=0){ count ++; } System.out.println(count); } } public static int highbit(int x){ for(int i=31;i>=0;i--) { int m = (x>>i)&1; if(m != 0) return i+1; } return 0; } }