A&C. Anu Has a Function
Codeforces Round #618 (Div. 1&2)
关键词
greedy math *1500 位运算
解题思路
这是我第一次解关于位运算的题,这题需要很多关于位运算的技巧,在比赛时我将英语单词OR
看成了XOR
,导致一直卡在这题上。
然后讲一下正确的解题思路,将原来的函数转化。
这是
f
(
11
,
6
)
f(11,6)
f(11,6)的计算过程,不难发现运算结果对于11来说就是使如果该位在6的二进制上对应的值是1那么这位就是0,否则不变,然后我们就可以得出
f
(
x
,
y
)
=
(
x
∣
y
)
−
y
=
x
&
(
∼
y
)
f(x,y)=(x|y)-y=x\&(\sim y)
f(x,y)=(x∣y)−y=x&(∼y)。
然后根据题意
f
(
f
(
…
f
(
f
(
a
1
,
a
2
)
,
a
3
)
,
…
a
n
−
1
)
,
a
n
)
f(f(\dots f(f(a_1, a_2), a_3), \dots a_{n-1}), a_n)
f(f(…f(f(a1,a2),a3),…an−1),an)就被化简成为了。
a 1 & ( ∼ a 2 ) & ( ∼ a 3 ) … & ( ∼ a n ) = a 1 & { ∼ ( a 2 ∣ a 3 ∣ … ∣ a n ) } (1) a_1\&(\sim a_2)\&(\sim a_3)\dots \&(\sim a_n)=a_1\&\{\sim (a_2|a_3|\dots |a_n)\}\tag{1} a1&(∼a2)&(∼a3)…&(∼an)=a1&{∼(a2∣a3∣…∣an)}(1)
根据位运算的交换律我们可以得出,若想使得
(
1
)
(1)
(1)式最大,只需要找到一个
a
1
a_1
a1和剩余的式子与最大即可。
接下来想一下最优解
a
1
a_1
a1对应的不交换之前的
a
k
a_k
ak怎样找。
还没交换之前:
a k & { ∼ ( a 1 ∣ a 2 ∣ … ∣ a k − 1 ) } & { ∼ ( a k + 1 ∣ a k + 2 ∣ … ∣ a n ) } = a k & { ∼ ( a 1 ∣ a 2 ∣ … ∣ a k − 1 ∣ a k + 1 ∣ a k + 2 ∣ … ∣ a n ) } a_k\&\{\sim (a_1|a_2|\dots|a_{k-1})\}\&\{\sim (a_{k+1}|a_{k+2}|\dots |a_n)\}\\=a_k\&\{\sim (a_1|a_2|\dots |a_{k-1}|a_{k+1}|a_{k+2}|\dots|a_n)\} ak&{∼(a1∣a2∣…∣ak−1)}&{∼(ak+1∣ak+2∣…∣an)}=ak&{∼(a1∣a2∣…∣ak−1∣ak+1∣ak+2∣…∣an)}
所以接下来就很简单了只需要求出每一个
a
1
∣
a
2
∣
…
∣
a
k
−
1
a_1|a_2|\dots |a_{k-1}
a1∣a2∣…∣ak−1和
a
k
+
1
∣
a
k
+
2
…
∣
a
n
a_{k+1}|a_{k+2}\dots |a_{n}
ak+1∣ak+2…∣an,然后记录令函数值最大的
k
k
k然后
a
1
a_1
a1与
a
k
a_k
ak交换输出数列即可。
时间复杂度为:
O
(
n
)
O(n)
O(n)
源码
#include <iostream>
using namespace std;
const int MAXN=(int)1e5+5;
const int INF=0x3f3f3f3f;
int n,val[MAXN],a1[MAXN],a2[MAXN],k,m,tmp;
int main()
{
cin>>n;
a1[0]=0;
for (int i = 1; i <= n; i++)
{
cin>>val[i];
a1[i]=val[i]|a1[i-1];
}
a2[n+1]=0;
k=INF,m=-INF;
for(int i=n;i>=1;i--)a2[i]=a2[i+1]|val[i];
for(int i=1;i<=n;i++)if((tmp=val[i]&~(a1[i-1]|a2[i+1]))>m)m=tmp,k=i;
cout<<val[k];
for(int i=1;i<=n;i++)if(i!=k)cout<<" "<<val[i];
cout<<endl;
return 0;
}