hdu 1695
题目:给出x和y的范围,要求gcd(x,y)==k的数对个数。
思路:首先把范围除k,然后就是求gcd(x,y)=1的数对个数。具体莫比乌斯公式的用法还不是很懂,目前的理解是这样的:
莫比乌斯公式给出了一个从和函数反演到原函数的方法。对于一个定义在正整数上的函数,其和函数F(n)定义为所有f(d)|d是n的因子的和。然后根据莫比乌斯公式,可由F求得f。
但是此题的形式有点不同。设f(k)表示gcd(x,y)=k的数对的个数。然后设F(k)表示gcd(x,y)=k的倍数的数对的个数。然后F是f的和函数,但是形式变成了这样:F(n)定义为所有f(d)|d是n的倍数的和。此时应用莫比乌斯函数的形式不变。
/* * @author: Cwind */ //#pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include <algorithm> #include <cstdio> #include <cstring> #include <cstdlib> #include <vector> #include <queue> #include <stack> #include <functional> #include <set> #include <cmath> using namespace std; #define IOS std::ios::sync_with_stdio (false);std::cin.tie(0) #define pb push_back #define PB pop_back #define bk back() #define fs first #define se second #define sq(x) (x)*(x) #define eps (1e-3) #define IINF (1<<29) #define LINF (1ll<<59) #define INF 1000000000 typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> pii; typedef pair<ll,ll> P; zconst int MAXN = 1000000; bool check[MAXN+10]; int prime[MAXN+10]; int mu[MAXN+10]; void Moblus(){ memset(check,false,sizeof(check)); mu[1] = 1; int tot = 0; for(int i = 2; i <= MAXN; i++){ if( !check[i] ){ prime[tot++] = i; mu[i] = -1; } for(int j = 0; j < tot; j++){ if(i * prime[j] > MAXN) break; check[i * prime[j]] = true; if( i % prime[j] == 0){ mu[i * prime[j]] = 0; break; } else{ mu[i * prime[j]] = -mu[i]; } } } } int a,b,c,d,k; int T; int cas=0; int main(){ freopen("/home/files/CppFiles/in","r",stdin); //freopen("defense.in","r",stdin); //freopen("defense.out","w",stdout); cin>>T; Moblus(); while(T--){ cin>>a>>b>>c>>d>>k; if(k==0){ printf("Case %d: 0\n",++cas); continue; } ll ans1=0,ans2=0; if(b>d) swap(b,d); b/=k,d/=k; for(int i=1;i<=b;i++){ ans1+=mu[i]*(ll)(b/i)*(d/i); } for(int i=1;i<=b;i++){ ans2+=mu[i]*(ll)(b/i)*(b/i); } printf("Case %d: %lld\n",++cas,ans1-ans2/2); } return 0; }
时间: 2024-10-12 22:32:30