解决这类题目的关键是深入了解 |, ^, ! ,& 操作的意义;
codeforces 244 Problem C. The Brand New Function
题目链接: http://www.codeforces.com/contest/244/problem/C
题意: 给出n的数据,连续一段数据做|可产生一个值,问有可产生多少个不同的值?
分析: 首先对|操作进行分析; 如 a|b,就是二进制位存在1的话,该位就为1.
101101 | 010010 = 111111; 这个性质是显而易见的。那么知道这个对本题有什么作用呢?对于当前数据a来分析,
a与哪些值做|操作会产生新值呢?要和a产生新值,那么很明显就要把a中是0的为改成1.怎么改?最直观的方法就是a与前面的数一个一个|起来就是了。 呵呵,要是你就直接这样写代码的话,我也不拦你(TLE的概率几乎为100%)。其实a和前面的数做|有很多都是不必要的操作,因为a的那些位本来就是1.那么如果有一个数组记录各个位最后出现的位置,那么a是不是可以直接和这些数据做|呢? 答案是肯定的。因为中间的值不会影响产生新值。但是要注意到a必须显赫数组里最后的那个位置做|,然后依次|。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
#define maxn 100008
int n;
int a[maxn];
const int full = 1<<20;
bool Is[full];
int pos[21]={-1};
set < int> last;
int Max, Min;
int main( ) {
while( cin >> n ) {
for ( int i=0; i<n; ++i ) cin >> a[i];
for ( int i=0; i<n; ++i ) {
Is[a[i] ] = true;
if(Min > a[i] ) Min = a[i];
if(Max < a[i] ) Max = a[i];
int tmp = a[i], cnt=0;
while( tmp ) {
++cnt;
if(tmp&1 ) pos[cnt] = i;
tmp >>= 1;
}
if(!last.empty() ){
set<int>::iterator s=last.end();
--s;
tmp = a[i];
for (; ; --s ){
Is[tmp|=a[*s] ] = true;
if(tmp > Max) Max = tmp;
if(tmp < Min) Min = tmp;
if(s == last.begin() ) break;
}
}
last.clear();
for ( int i=1; i<=20; ++i )
if(pos[i] != -1) last.insert( pos[i] );
}
int ans = 0;
for ( int i=Min; i<=Max; ++i ) ans += Is[i];
cout << ans << endl;
}
}
代码写的很挫跑了600+ms;
codeforces 165 E. Compatible Numbers
题目链接: http://codeforces.com/contest/165/problem/E
题意: 给出n个数据,对于每个数求和数据做&操作结果为0的数,且结果必须是数组中的数;
分析: 每个数据都是不大于4*10^6的,就是说22位就可以记录所有的状态;
假设数据为:x的结果为y,那么与x等价的数的结果也为y;什么是等价呢?
比如说; 101001 和 101000就是等价的;
dp[s^(1<<i)] = dp[s] ;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 1000011;
const int full = (1<<22)-1;
int dp[full]={-1}, a[maxn], n;
int main( ) {
while( cin >> n ) {
memset(dp, -1, sizeof dp);
for ( int i=0; i<n; ++i ) {
cin >> a[i];
dp[full^a[i] ] = a[i];
}
for ( int i=full-1; i>=0; --i ) if( ~dp[i] ) {
for ( int j=0; j<22; ++j ) if(i&(1<<j) ) {
dp[i^(1<<j)] = dp[i];
}
}
for ( int i=0; i<n; ++i ) {
if(i ) putchar(' ');
cout << dp[a[i] ];
}puts("");
}
}
耗时2000+