1. 程式人生 > >【NOIP2015模擬】終章-劍之魂

【NOIP2015模擬】終章-劍之魂

背景介紹

古堡,暗鴉,斜陽,和深淵……
等了三年,我獨自一人,終於來到了這裡……
“終焉的試煉嗎?就在這裡嗎?”我自言自語道。
“終焉的試煉啊!就在這裡啊!”我再一次自言自語道。
“這背後可能有那個東西嗎?”我自言自語道。
“這背後一定有那個東西呢!”我又一次自言自語道。
我沉默著,踏上黑漆漆的索橋,小心翼翼地,拿出鋒利的注入我靈魂的雙劍……
“那麼,我們開始吧……”我最後一次自言自語道。

題目描述

My soul of my sowrd!
終焉的試煉即將到來,作為一名有修養的劍士,雖然沒有習得n刀流但是二刀流還是沒問題的。然而我也是個劍的收藏者,家裡屯著n把劍,每一把劍都有一個靈魂值a[i],由於一些劍之間可能有共鳴,所以我需要兩把契合度最高的劍。據劍聖所說,兩把編號為i,j劍的契合度為a[i] and a[j]。如何深得劍的靈魂呢?
注:AND 為按位與運算,先將數轉成二進位制,不滿位數的補全0,然後成為兩個長度相同的二進位制數,處理的時候,兩個相應的二進位制位都為1,該位的結果值才為1,否則為0。例:0101(5) and 0011(3)=0001(1)

輸入

第一行一個整數n,代表藏劍數。
第二行n個整數,第i個整數表示a[i]。

輸出

輸出包含一個正整數,最好的兩把劍的契合度。

思路

我們先測試幾組資料。1.6 and 4=4. 2.6 and 2=2. 3.4 and 2=0.不難發現,兩個數越大,運算出來結果越大。由此得出解法。

解法+時間複雜度

先從大到小快排(n log n),再n^2列舉。WTF!這你都過了?別急,聽完嘛。如果我們and出來的數沒上一次大,後面的數and出來一定沒有這次大,我們就可以break了。所以總時間複雜度為O(n log n+玄(學))

#include<cstdio>
#include<iostream> #include<cstring> using namespace std; int n,i,u,k,a[1000001],b[1000001][32],xh,h[32][32],j,o[1000001]; long long ans; bool bz,bj[1000001]; int ks(long long x) { if (x==0) return 1; if (x==1) return 2; else { int s=x%2; if (s==1) return ks(x/2)*ks(x/2)*2;else return
ks(x/2)*ks(x/2); } } int main() { freopen("sword.in","r",stdin); freopen("sword.out","w",stdout); scanf("%d",&n); for (i=1;i<=n;i++) { scanf("%d",&a[i]); while (a[i]!=0) { b[i][0]++; b[i][b[i][0]]=a[i]%2; a[i]/=2; } xh=max(xh,b[i][0]); h[b[i][0]][0]++; h[b[i][0]][h[b[i][0]][0]]=i; } bz=0; for (i=xh;i>=1;i--) { if (bz==0) { k+=h[i][0]; for (j=1;j<=h[i][0];j++) { bj[h[i][j]]=1; } } u=0; for (j=1;j<=n;j++) if (b[j][i]==1 && bj[j]==1) u++;else { o[0]++; o[o[0]]=j; } if (u>=2) { ans+=ks(i-1); for (j=1;j<=o[0];j++) bj[o[j]]=0; bz=1; } memset(o,0,sizeof(o)); } printf("%lld",ans); }