题意:
t组数据,每组数据给出一个[l,r]的范围,通过删去其中的数,使得剩下的数通过与运算的值不为0.输出删去个数最小的。
思路:
在写的时候,没有想那么多,直接进行计算[l,r]中出现的二进制位数上为1的个数,然后找到所有位数上个最多的,结果就是r-l+1-max.就这样很愉快的TLE了。
正确做法:通过前缀和处理出[1,2e5]中二进制中所有位数上为1的个数
TLE代码:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<stack>
#include<math.h>
#include<map>
#include<stdlib.h>
#include<queue>
using namespace std;
const int N=2e5+10;
int t,l,r;
int st[N];
int main()
{
scanf("%d",&t);
while(t--)
{
memset(st,0,sizeof(st));
scanf("%d%d",&l,&r);
int maxx=0;
for(int i=l;i<=r;i++)
{
int x=i;
int o=0;
while(x)
{
o++;
if(x%2)st[o]++;
x/=2;
}
maxx=max(o,maxx);
}
int op=0;
for(int i=1;i<=maxx;i++)
{
op=max(op,st[i]);
}
printf("%d\n",r-l+1-op);//删掉多少个数;
}
return 0;
}
正确做法:
#include<iostream>
#include<stack>
#include<stdio.h>
#include<queue>
#include<map>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e6+10;
int t,l,r;
int f[N][30];//先预处理
void init()
{
for(int i=1;i<=2e5;i++)
{
for(int j=0;j<=30;j++)
{
if(i>>j&1)//是1的时候
f[i][j]=f[i-1][j]+1;
else
f[i][j]=f[i-1][j];
}
}
}
int main()
{
init();
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&l,&r);//表示范围;
int res=0;
for(int i=0;i<=30;i++)
{
int tt=f[r][i]-f[l-1][i];
res=max(res,tt);//最多的;
}
printf("%d\n",r-l+1-res);
}
return 0;