• 序列【模拟】


    题目大意:

    在这里插入图片描述


    思路:

    首先,我们知道a or ba or b肯定是不小于a和b,也就是说,进行或运算的数字越多,结果肯定不会变小。所以,第一问的答案就是全部数字或起来。
    那么就考虑第二问。
    由于进行与运算的两个数a,ba,b肯定有a and bmin(a,b)a and bleq min(a,b),所以进行与运算的数字越多,结果肯定不会变大。所以最好就选择kk个数。
    可以把选择的数看成一个滑动窗口,那么就用num[i]num[i]表示现在窗口的数字中有多少个是二进制下第ii位为11的。
    例如窗口里有33个数11,8,211,8,2,那么将这三个数分别转成二进制后就是

    1111 88 22
    10111011 10001000 00100010

    所以

    • num[0]=1+0+0=1num[0]=1+0+0=1
    • num[1]=1+0+1=2num[1]=1+0+1=2
    • num[2]=0+0+0=0num[2]=0+0+0=0
    • num[3]=1+1+0=2num[3]=1+1+0=2

    那么如果num[x]==mnum[x]==m,说明窗口里的数字这一位全部是11,所以andand起来就是11,否则不是。
    那么就求出窗口在最左边的情况的答案,然后往右移即可。
    时间复杂度:(常数为3030的)O(n)O(n),时限5s5s,不怂。


    代码:

    #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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    生命
    历史的分岔-中日产业发展史的对照和思考
    挑战自已
    丰台往事已成风,上下求索永不停
    VC6.0实现鼠标光标形状及大小的定制
    RelativeLayout
    16进制颜色代码
    html里的option错误
    Android用户界面设计:布局基础
    Activity详细介绍【官网】
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998490.html
Copyright © 2020-2023  润新知