A&C. Anu Has a Function

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)=(xy)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),an1),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&{(a2a3an)}(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&{(a1a2ak1)}&{(ak+1ak+2an)}=ak&{(a1a2ak1ak+1ak+2an)}

所以接下来就很简单了只需要求出每一个 a 1 ∣ a 2 ∣ … ∣ a k − 1 a_1|a_2|\dots |a_{k-1} a1a2ak1 a k + 1 ∣ a k + 2 … ∣ a n a_{k+1}|a_{k+2}\dots |a_{n} ak+1ak+2an,然后记录令函数值最大的 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值