[2020.7.24NOIP提高组模拟T3]终章-剑之魂

【题目描述】

终焉的试炼即将到来,作为一名有修养的剑士,虽然没有习得n刀流但是二刀流还是没问题的。然而我也是个剑的收藏者,家里屯着n把剑,每一把剑都有一个灵魂值a[i],由于一些剑之间可能有共鸣,所以我需要两把契合度最高的剑。据剑圣所说,两把编号为i,j剑的契合度为a[i] & a[j]。如何深得剑的灵魂呢?

 

【输入】

第一行一个整数n,代表藏剑数。

第二行n个整数,第i个整数表示a[i]。

【输出】

输出包含一个正整数,最好的两把剑的契合度。

 

【样例输入】

5
12  5  6  3  1

【样例输出】

4

 

【数据范围】

对于40%的数据 n ≤ 1,000
对于100%的数据 n ≤ 1,000,000,0 ≤ a[i] < 231

 

【解题思路1】

直接枚举所有情况,时间复杂度O(n2),会超时,得分40分

 

【解题思路2】

思路1的优化,先用sort将a[i]从大到小排列,因为ans的值为a[i]&a[j]的最大值,所以,当 ans>=a[i] 或 ans>=a[j] 时,小于等于ans的a数组的值(包括a[i]和a[j])无法使ans的值变大,所以跳过(break)

实际时间复杂度为O(n log n)+O(玄学)

最坏情况下时间复杂度会退化为O(n2),但由于本题数据过水,能得100分

 

#include<bits/stdc++.h>
#include<fstream>
using namespace std;
int n,ans;
int w[1000005];
ifstream fin("sword.in");
ofstream fout("sword.out");
inline bool cmp(int a,int b){
    return a>b;
}
int main(){
    fin>>n;
    for(int i=1;i<=n;i++)
        fin>>w[i];
    sort(w+1,w+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(w[i]<=ans) break;
        for(int j=i+1;j<=n;j++){
            if(w[j]<=ans) break;
            ans=max(ans,w[i]&w[j]);
        } 
    }    fout<<ans;
    return 0;
}

 

【解题思路3】(正解)

无需排序,时间复杂度O(30*n)

易知:1+2+4+……+2^(n-1)< 2^n

因此,就算只有从右往左第n位取1,取得的值也比倒数第1位到第(n-1)位全取1大(高位的数能取必须取)

因为 a[i]<2^31 ,所以先从高位(倒数第 i=30 位)枚举到低位(倒数第i=0 位),再枚举 a[j](j=1~n)

如果现在的 ans & a[j]==ans ,说明a[j]不会使ans的值变小

再如果 a[j] & (1<<i)>0 ,即a[j]的二进制从右往左第(i+1)取1,表示a[j]有可能使ans的值变大。

如果满足以上两种情况的a[j]有不少于两组,表示ans可以被满足以上两种情况的 a[j] &a[j+x] (x不定)更新 ,更新后的ans比更新前至少大(1<<i)(回看第二种情况)。

 

#include<bits/stdc++.h>
#include<fstream>
using namespace std;
int n,ans;
int w[1000005];
ifstream fin("sword.in");
ofstream fout("sword.out");
int main(){
    fin>>n;
    for(int i=1;i<=n;i++)
        fin>>w[i];
    for(int i=30;i>=0;i--){
        int dsc=0;
        for(int j=1;j<=n;j++)
            if(((ans&w[j])==ans)&&(w[j]&(1<<i))) ++dsc;
        if(dsc>=2) ans+=(1<<i);
    }
    fout<<ans;
    return 0;
}

 

2020-07-24

posted @ 2020-07-24 18:32  离月无言  阅读(50)  评论(0编辑  收藏  举报