hdu 2841 Visible Trees
题意是给定一个n*m的网格 每一个点上都有一棵树 问从(0,0)点能够看到几棵树
从(0,0)点看过去 如果有重叠的树 只能看到离自己最近的那一个
如果能看到点(x,y)的树 那么(k*x,k*y) 对于k>1 (k*x,k*y)上的树都不能看到
问题就可以转化为在1<=x<=n,1<=y<=m中有多少个(x,y)满足gcd(x,y)=1
在1-n枚举x 累计在1-m中有多少个y与x互素
枚举x 就可以把问题转化为在一个范围内有多少个数与y互素
然后问题就跟上一篇写的差不多了
解决这个问题时 预处理出 数据范围之内 每个数所拥有的数因子。。
size就是这个数素因子的个数
然后用容斥原理 求个数
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
vector<int> pri[MAXN];
void init()
{
for(int i=0;i<MAXN;i++)
pri[i].clear();
for(int i=2;i<MAXN;i++)
{
if(pri[i].size())
continue;//如果size不为0 说明i可以分解为两个数的乘积
//为0说明之前的数都不能整除它
//size表示素因子的个数
pri[i].push_back(i);
for(int j=2;i*j<MAXN;j++)
{
pri[i*j].push_back(i);
}
}
}
ll ans(ll order,ll m)
{
int s=pri[order].size();
ll res=0;
for(ll i=1;i<(ll)(1<<s);i++)
{
int flag=0;
ll tmp=1;
for(int j=0;j<s;j++)
{
if(i&(ll)(1<<j))
{
flag++;
tmp*=(ll)pri[order][j];
}
}
if(flag&1)
res+=m/tmp;
else res-=m/tmp;
}
return res;
}
int main()
{
//freopen("ceshi.txt","r",stdin);
init();
int tc;
scanf("%d",&tc);
while(tc--)
{
ll m,n;
scanf("%I64d%I64d",&m,&n);
ll res=0;
res+=n;
for(ll i=2;i<=m;i++)
{
res+=ans(i,n);
}
printf("%I64d\n",res);
}
return 0;
}
hdu 1695 GCD
题意就是求在1<=a<=x 1<=b<=y 中满足gcd(a,b)=k的(a,b)的对数 注意 是无序的
问题转化为在[1,x/k]和[1,y/k]范围内找gcd(a,b)=1的对数 (如果gcd(a,b)=k 那么gac(a/k,b/k)=1)
因为给定5个参数 a b c d k 其中 a c 是等于1的 b/=k d/=k 修改参数范围
令b=min(b,d) 然后用欧拉函数直接求出 1-b范围内所有数的欧拉函数的和
这里可以减少 枚举次数
在 b+1-d范围内的数 通过上题的 方法进行求和!!!
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
#define eps 1e-8
#define op operator
#define MOD 10009
#define MAXN 100100
#define INF 0x7fffffff
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define FOV(i,a,b) for(int i=a;i>=b;i--)
#define REP(i,a,b) for(int i=a;i<b;i++)
#define REV(i,a,b) for(int i=a-1;i>=b;i--)
#define MEM(a,x) memset(a,x,sizeof a)
#define ll __int64
using namespace std;
vector<int> pri[MAXN];
void init()
{
for(int i=0;i<MAXN;i++)
pri[i].clear();
for(int i=2;i<MAXN;i++)
{
if(pri[i].size())
continue;//如果size不为0 说明i可以分解为两个数的乘积
//为0说明之前的数都不能整除它
//size表示素因子的个数
pri[i].push_back(i);
for(int j=2;i*j<MAXN;j++)
{
pri[i*j].push_back(i);
}
}
}
ll ans(ll order,ll m)
{
int s=pri[order].size();
ll res=0;
for(ll i=1;i<(ll)(1<<s);i++)
{
int flag=0;
ll tmp=1;
for(int j=0;j<s;j++)
{
if(i&(ll)(1<<j))
{
flag++;
tmp*=(ll)pri[order][j];
}
}
if(flag&1)
res+=m/tmp;
else res-=m/tmp;
}
return m-res;
}
int phi(int n)
{
int res=n;
for(int i=2;i*i<=n;i++)
{
if(n%i==0)
{
res=res-res/i;
while(n%i==0)
{
n/=i;
}
}
}
if(n>1)
res=res-res/n;
return res;
}
int main()
{
//freopen("ceshi.txt","r",stdin);
init();
int tc;
scanf("%d",&tc);
int cs=1;
while(tc--)
{
ll a,b,c,d,k;
ll res=0;
scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&k);
printf("Case %d: ",cs++);
if(k==0)
{
printf("0\n");
continue;
}
if(d<b)//让b取小值
swap(b,d);
for(int i=1;i<=b/k;i++)
res+=phi(i);
for(ll i=b/k+1;i<=d/k;i++)
{
// cout<<"ans "<<ans(i,b)<<endl;
res+=ans(i,b/k);
}
printf("%I64d\n",res);
}
return 0;
}