题意:
有N个人排成一排,从1到N按顺序依次编号,现在要执行N次操作,第一次操作让所有的人都蹲下,之后第二次操作让编号是2和2的倍数的人全部站起来,然后第三次操作让编号是3和3的倍数的人全部做相反的动作(站着的人蹲下,蹲下的人站起来),以此类推…,最后第N此操作让编号为N的这个人也做相反的动作。请问N次操作后,从第A个人到第B个人之间(包括A和B这两个数字,且A<B)有多少人是站着的?
思路1:(模拟/暴力)
#include<bits/stdc++.h>
using namespace std;
const int inf= 0x3f3f3f3f;
typedef long long ll;
int cn[1000000+10];
void init()
{
memset(cn,-1,sizeof cn); // 1站起来 -1蹲下
for(int i=2;i<=1000000;i++)
{
for(int j=i;j<=1000000;j+=i)
cn[j] = -cn[j];
}
}
int main()
{
int t;cin>>t;
init();
while(t--)
{
int n,a,b;
cin>>n>>a>>b;
int cnt=0;
for(int i=a;i<=b;i++) if(cn[i]==1) cnt++;
cout<<cnt<<endl;
}
}
思路2(找规律):(用前缀和/树状数组可以优化时间复杂度)
(n=1 size=1)
(n=2 size=2)
(n=3 size=2)
(n=4 size=3)
(n=5 size=2)
(n=6 size=4)
(n=7 size=2)
(n=8 size=4)
(n=9 size=3)
(n=10 size=4)
(n=11 size=2)
(n=12 size=6)
(n=13 size=2)
(n=14 size=4)
(n=15 size=4)
(n=16 size=5)
(n=17 size=2)
(n=18 size=6)
(n=19 size=2)
(n=20 size=6)
(n=21 size=4)
(n=22 size=4)
(n=23 size=2)
(n=24 size=8)
(n=25 size=3)
(n=26 size=4)
(n=27 size=4)
(n=28 size=6)
因此 易知 若n为可开方数 则有奇数个因数
#include <stdio.h>
#include <math.h>
int zcs[1000001];
int main()
{
int t, zz;
int i, j, n, a, b;
scanf("%d", &t);
while (t--)
{
int count = 0;
scanf("%d %d %d", &n, &a, &b);
zz = sqrt(n);
for (i = 1; i <= zz; i++)
{
zcs[i * i] = 1;
}
for (i = a; i <= b; i++)
{
if (!zcs[i]) count++;
}
printf("%d\n", count);
}
return 0;
}