About Problem
- The web : http://www.lydsy.com/JudgeOnline/problem.php?id=3668
- The tab : 二进制,NOI
Solve
题目的意思就是给你一些操作C[1] - C[N],每个操作只有可能是AND(&), OR(|), XOR(^)中的一个。
然后给你一个数M。
设f(x)为 x 经过操作 C[1] - C[N] 后的得到的答案。
要求:
Score 50%
其实这个就很简单的,枚举每一个M,然后去跑N个步骤,然后找出最优解就可以。
复杂度O(M * N)
Code:
#include <cstdio>
#include <cstring>
#ifdef _WIN32
#define lld I64d
#endif
const int Maxn = int(1e5) + 10;
int n, m, t[Maxn], com[Maxn];
int ans = 0;
void force1()
{
for(int i = 0; i <= m; ++i)
{
int tmp = i;
for(int j = 1; j <= n; ++j)
if(com[j] == 1) tmp = tmp & t[j];
else if(com[j] == 2) tmp = tmp | t[j];
else if(com[j] == 3) tmp = tmp xor t[j];
if(tmp > ans) ans = tmp;
}
printf("%d\n", ans);
return;
}
int main()
{
freopen("sleep.in", "r", stdin);
freopen("sleep.out", "w", stdout);
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i)
{
char s[5];
scanf("%s %d", s, &t[i]);
if(s[0] == 'A') com[i] = 1;
else if(s[0] == 'O') com[i] = 2;
else if(s[0] == 'X') com[i] = 3;
}
if(m <= 1000) force1();
return 0;
}
Score 100%
既然M高达1e9,那么很明显不能枚举M了。
那我们换个思路,既然这里都是二进制计算,那么这些二进制计算有一个非常显著的特点,就是它的每一位都是相对独立的。
举个例子来说:
6 = 1 1 0
5 = 1 0 1
6 ^ 5 = 0 1 1
当你在计算从左往右数第2位时, 第一位和第三位均不会影响第二位的运算结果。
我们假设最后的答案是从 K 经过N步后得到的 f(K)。
那么我们是不是可以枚举 K 的每一个二进制位,然后看 K 的第 i 个二进制位为1更优 还是为0更优。
最后得到每一个二进制位的最有值,在贪心选取,看看得到的K会不会超过M。
再求出f(K)就OK了。
由于答案在1e9内,所以不会超过32位。
每位可以进行N次操作,所以复杂度为O(32 * N)
Code:
#include <cstdio>
#include <cstring>
const int Maxn = (int)1e5 + 10;
int num[Maxn][40], t[Maxn], ans[40];
int N = 0;
int main()
{
freopen("sleep.in", "r", stdin);
freopen("sleep.out", "w", stdout);
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i)
{
char s[5];
scanf("%s %d", s, &t[i]);
if(s[0] == 'A') num[i][0] = 1;
else if(s[0] == 'O') num[i][0] = 2;
else if(s[0] == 'X') num[i][0] = 3;
int tmp = t[i], l = 0;
while(tmp)
{
num[i][++l] = tmp % 2;
tmp /= 2;
}
}
for(int i = 31; i; --i)
{
int z = 0, o = 1;
for(int j = 1; j <= n; ++j)
{
if(num[j][0] == 1) z &= num[j][i], o &= num[j][i];
else if(num[j][0] == 2) z |= num[j][i], o |= num[j][i];
else if(num[j][0] == 3) z = z xor num[j][i], o = o xor num[j][i];
}
if(o > z) ans[i] = 1;
else ans[i] = 0;
}
for(int i = 31; i; --i)
if(N + (ans[i] << (i-1)) <= m) N += (ans[i] << (i - 1));
for(int i = 1; i <= n; ++i)
{
if(num[i][0] == 1) N &= t[i];
else if(num[i][0] == 2) N |= t[i];
else if(num[i][0] == 3) N ^= t[i];
}
printf("%d\n", N);
return 0;
}