About Problem
- The web : http://www.lydsy.com/JudgeOnline/problem.php?id=3668
- The tab : 二進(jìn)制,NOI
Solve
題目的意思就是給你一些操作C[1] - C[N],每個操作只有可能是AND(&), OR(|), XOR(^)中的一個。
然后給你一個數(shù)M。
設(shè)f(x)為 x 經(jīng)過操作 C[1] - C[N] 后的得到的答案。
要求:
Score 50%
其實(shí)這個就很簡單的,枚舉每一個M,然后去跑N個步驟,然后找出最優(yōu)解就可以。
復(fù)雜度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高達(dá)1e9,那么很明顯不能枚舉M了。
那我們換個思路,既然這里都是二進(jìn)制計算,那么這些二進(jìn)制計算有一個非常顯著的特點(diǎn),就是它的每一位都是相對獨(dú)立的。
舉個例子來說:
6 = 1 1 0
5 = 1 0 1
6 ^ 5 = 0 1 1
當(dāng)你在計算從左往右數(shù)第2位時, 第一位和第三位均不會影響第二位的運(yùn)算結(jié)果。
我們假設(shè)最后的答案是從 K 經(jīng)過N步后得到的 f(K)。
那么我們是不是可以枚舉 K 的每一個二進(jìn)制位,然后看 K 的第 i 個二進(jìn)制位為1更優(yōu) 還是為0更優(yōu)。
最后得到每一個二進(jìn)制位的最有值,在貪心選取,看看得到的K會不會超過M。
再求出f(K)就OK了。
由于答案在1e9內(nèi),所以不會超過32位。
每位可以進(jìn)行N次操作,所以復(fù)雜度為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;
}