问题描述
xiaoz最近想出来一个新的游戏,现在又n的灯泡,他们的编号是1~n,xiaoz说每次说两个数,找出他们的公共质因子,且每次把他们公共质因子的倍数编号灯泡的相反状态。(原开按为关,原关按为开)
输入
有多组数据,先输入t,n,有t组测试数据同时有n(2<=n<1000 000)灯泡,每组数据有多对数,当输入为"0 0" 时,这组测试结束。(开始时灯泡都是开的)
输出
输出两组灯泡数n,且每组占一行。
样例输入
1 100
2 3
0 0
样例输出
100
提示:又肯存在一个灯泡在一次输入中会更新多次
题解:
第一步:用筛选法求出1~1000 000 的素数,并且用一个数组储存这些素数
第二步:开一个1000 000的数组,对数组进行初始化(用0 1表示)
第三步:找出输入数对的质因子(枚举)
第四步:对公共质因子的倍数的灯泡进行更新
第五步:进行累加,将所有亮的灯泡加起来。
代码如下:
#include<iostream>
#include<stdio.h>
#include<math.h>
using namespace std;
int p[1000030],ip[100020],num[1000010];
int k,sum;
int main()
{
for(int i=2;i<=1000000;i++)
{
p[i]=0;
}
for(int i=2;i<1000;i++)
{
if(!p[i])
{
for(int j=2*i;j<=1000000;j+=i)
{
p[j]=1;
}
}
}
k=0;
for(int i=2;i<=1000000;i++)
{
if(!p[i])
{
ip[k++]=i;
}
}
/* for(int i=0;i<k;i++)
{
cout<<ip[i]<<" ";
}*/
//以上是筛选法求1000000以内的素数
int t,n;
cin>>t;
int a1,a2;
int tm,min;
while(t--)
{
cin>>n;
for(int i=1;i<=n;i++)
{
num[i]=1;//开始时将所有的灯标为1
}
while(cin>>a1>>a2)
{
if(a1==0&&a2==0)
{
break;
}
if(a1>a2)
{
min=a2;
}
else
{
min=a1;//求出最小值
}
for(int i=0;i<k;i++)//在K个素数内寻找
{
if(ip[i]<min)//以a1 a2的最小的那个为临界值
{
if(a1%ip[i]==0&&a2%ip[i]==0)//如果ip[i]的素数值能够被a1 a2同时整除
{
tm=ip[i];//记录此值
for(int j=tm;j<=n;j+=tm)//寻找此值的倍数,他的倍数也将被标记
{
if(num[j])//如果此灯是1则改为零
{
num[j]=0;
}
else//如果是零则改为1
{
num[j]=1;
}
}
}
}
}
}
sum=0;
for(int i=1;i<=n;i++)
{
sum=sum+num[i];//将所有为1的数加起来
}
cout<<sum<<endl;
}
return 0;
}