HDU-1695(水题3)

メビウス反転エントリーのタイトル

最後に、水問題大物口(I C A)

問題の意味:あなたの5つの数A、B、C、D 、K、 二つの数は、2つのセクションABおよびCDをxからGCD(x、y)はkに等しくなるように、Y、それぞれ採取したが、尋ねます((x、y)と(X、Y)と同じ)数の(x、y)は
、cは1つのプロセスである場合タイトルは特に顕著。

溶液は: - B 1 - 1ためのB / Kと1 - - 2つの数のそのGCDがまあをkに等しくなるように、Dが選択され、簡単に1に変換するD / Kの素数の数の、我々組F(t)は数の(x、y)は、T(x、y)に等しく、GCDに等しく、F(t)は(x、y)は、T(x、y)の複数を=番号GCDに等しく、描画することが容易ですF(N)=ΣF( D)(N | d)は、 第二メビウス反転式に従って我々は、Fを締結することができる(N)=Σ(MOB [D / N] * F [D]) (N | D)、そして私たちの以前の結論によると、私たちはライン上のF(1)を求めるためにここにいます。
慎重について、我々はFを見つけることができると思います(X)=(B / X)*(D / x)は、 コードを提供します。

//#pragma GCC optimize(3,"Ofast","inline")
//#include<unordered_map>
//#include<unordered_set>
#include<cstdio>
#include<iostream>
#include<cmath>
#include<functional>
#include<cstring>
#include<string>
#include<cstdlib>
#include<queue>
#include<map>
#include<algorithm>
#include<set>
#include<stack>
#include<vector>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
const int maxn=1e5+10;
const ll mod=1e9+7;
ll prime[maxn],isprime[maxn];
ll mob[maxn];
ll num;
void getmobius()
{
    memset(prime,0,sizeof(prime));
    memset(mob,0,sizeof(mob));
    memset(isprime,1,sizeof(isprime));
    mob[1]=1;
    for(int i=2;i<=100000;i++)
    {
        if(isprime[i])
        {
        	prime[num++]=i;
        	mob[i]=-1;
        }
        for(int j=0;j<num&&i*prime[j]<=100000;j++)
        {
            isprime[i*prime[j]]=0;
            if(i%prime[j]==0)
            {
            	mob[i*prime[j]]=0;
            	break;
            }
            else mob[i*prime[j]]=-mob[i];
        }
    }
}

int main()
{
    ll t;
    getmobius();
    scanf("%lld",&t);
    ll a,b,c,d,k;
    int K=0;
    while(t--)
    {
        scanf("%lld%lld%lld%lld%lld",&a,&b,&c,&d,&k);
        if(k==0)
        {
            printf("Case %d: 0\n",++K);
            continue;
        }
        b/=k;d/=k;
        ll ans1,ans2;
        ans1=ans2=0;
        for(ll i=1;i<=min(b,d);i++)ans1+=mob[i]*(b/i)*(d/i);//这里求的是所有的情况,但是(x,y)和(y,x)是一样的情况,所以这不是最终答案
        for(ll i=1;i<=min(b,d);i++)ans2+=mob[i]*(min(b,d)/i)*(min(b,d)/i);//这里求的是1-b和1-d重叠部分的所有情况
        ans1=ans1-ans2/2;//我们这样想,ans1代表的是所有情况,重叠部分可以说是都算了两次,非重叠部分很正常,只算了一次,然后我们讲ans1减去一个ans/2,就是减去一半的重叠部分,最后就是一个重叠部分和一个非重叠部分的最终答案了!(有点像容斥原理)
        printf("Case %d: %lld\n",++K,ans1);
    }
    return 0;
}
公開された12元の記事 ウォンの賞賛0 ビュー274

おすすめ

転載: blog.csdn.net/zhlnb/article/details/104356571