There are many trees forming a m * n grid, the grid starts from (1,1). Farmer Sherlock is standing at (0,0) point. He wonders how many trees he can see.
If two trees and Sherlock are in one line, Farmer Sherlock can only see the tree nearest to him.
Input
The first line contains one integer t, represents the number of test cases. Then there are multiple test cases. For each test case there is one line containing two integers m and n(1 ≤ m, n ≤ 100000)
Output
For each test case output one line represents the number of trees Farmer Sherlock can see.
Sample Input
2
1 1
2 3
Sample Output
1
5
题意:在m*n的方格中,每个里面有一棵树(从(1,1)到(m,n)),你在(0,0),问可以看到几棵树。
思路:这道题的话,因为当两棵树在一条直线上的时候我们看不到,所以我们判断一下一个点(x,y)能被看到的条件。就是当x,y互质的时候,这颗树才能被看见。所以问题就转换成了有多少对坐标是互质的。可以通过枚举x,看有几个y与其互质累加。这样问题就又变成,区间有几个数与某个数互质,就转变成了经典的容斥问题。
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
const int maxx=100010;
const int inf=0x3f3f3f3f;
using namespace std;
int p[maxx];
int k;
void getp(ll n)
{
k=0;
for(ll i=2; i*i<=n; i++)
{
if(n%i==0)
{
p[k++]=i;
while(n%i==0)
n/=i;
}
}
if(n>1)
p[k++]=n;
}
ll nop(ll m)
{
ll top=0;
ll que[maxx];
ll t;
que[top++]=-1;
for(int i=0; i<k; i++)
{
t=top;
for(int j=0; j<t; j++)
{
que[top++]=que[j]*p[i]*(-1);
}
}
ll sum=0;
for(ll i=1; i<top; i++)
sum+=(m/que[i]);
return sum;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
ll m,n;
scanf("%lld%lld",&m,&n);
if(m>n)
swap(m,n);
ll ans=0;
for(ll i=1; i<=m; i++)
{
getp(i);
ans+=(n-nop(n));
}
printf("%lld\n",ans);
}
return 0;
}
下面再给出容斥原理的二进制版(位运算)模板:
#include <bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int lcm(int a,int b)
{
return a*b/gcd(a,b);
}
int solve()//求1~n与n互质的数的个数
{
int prime[10]= {2,3,5};
int n=30,ans,num;
ans=0,num=3;//num是素数因子或者因子的个数,这里是素数因子
for(int i=1; i< (1<<num) ; i++)//循环次数,也就是集合个数,也就是有2^num-1个集合
{
//i就是表示第i个集合
//2^n可以用1<<n为运算表示
int mult=1,cnt=0;
for(int j=0; j<num; j++) //循环prime中的每个元素
{
if(i & (1<<j))//要掌握&运算,与i的二进制的第j位比较,看是否为1,是则选中
{
cnt++;//记录集合中元素的个数
mult = lcm(mult,prime[j]);//是否要lcm看情况
}
}
if(cnt&1)//集合元素个数为奇数就加,否则减
ans += n/mult;
else
ans -= n/mult;
}
return n-ans;
}
int main()
{
cout<<solve();
return 0;
}
用位运算模板AC本题的代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int fac[100000];
int div(int n)
{
int cnt=0;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
fac[cnt++]=i;
while(n%i==0) n/=i;
}
}
if(n>1) fac[cnt++]=n;
return cnt;
}
int solve(int n,int cnt)
{
int ans=0;
for(int i=1;i< (1<<cnt);i++)
{
int ones=0,mult=1;
for(int j=0;j<cnt;j++)
{
if(i & (1<<j))
{
ones++;
mult*=fac[j];
}
}
if(ones &1)
ans+= n/mult;
else
ans-= n/mult;
}
return n-ans;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m;
ll ans=0;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int cnt=div(i);
ans+= solve(m,cnt);
}
cout<<ans<<endl;
}
return 0;
}