序列【模擬】
阿新 • • 發佈:2018-11-10
題目大意:
思路:
首先,我們知道
肯定是不小於a和b
,也就是說,進行或運算的數字越多,結果肯定不會變小
。所以,第一問的答案就是全部數字或起來。
那麼就考慮第二問。
由於進行與運算的兩個數
肯定有
,所以進行與運算的數字越多,結果肯定不會變大
。所以最好就選擇
個數。
可以把選擇的數看成一個滑動視窗,那麼就用
表示現在視窗的數字中有多少個是二進位制下第
位為
的。
例如窗口裡有
個數
,那麼將這三個數分別轉成二進位制後就是
所以
那麼如果
,說明窗口裡的數字這一位全部是
,所以
起來就是
,否則不是。
那麼就求出視窗在最左邊的情況的答案,然後往右移即可。
時間複雜度:(常數為
的)
,時限
,不慫。
程式碼:
#include <cstdio>
#include <iostream>
#define N 1000100
#define MAXN 40
using namespace std;
int n,m,a[N],ans,num[MAXN];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
ans|=a[i];
}
printf("%d ",ans); //第一問
for (int i=1;i<=m;i++)
for (int j=0;j<=30;j++)
if ((a[i]&(1<<j))==(1<<j)) num[j]++; //視窗
ans=0;
for (int i=m+1;i<=n;i++)
{
int k=0;
for (int j=0;j<=30;j++)
{
num[j]-=((a[i-m]&(1<<j))==(1<<j));
num[j]+=((a[i]&(1<<j))==(1<<j)); //右移
if (num[j]==m) k+=(1<<j); //求答案
}
if (ans<k) ans=k;
}
printf("%d\n",ans);
return 0;
}