HackerRank Weekly Challenges - Week 3 5問目 - GCD Product

Source

HackerRank Weekly Challenges - Week 3 5問目
problem statement(コンテストページ)
problem statement

問題概要

正整数 $N,M$ が与えられるので,
$\displaystyle \quad \prod_{i=1}^N \prod_{j=1}^M {\rm GCD}(i,j)$
の値を ${\rm mod}\ 1000000007\ (10^9+7)$ で求める問題.

解法

まず,${\rm GCD}(i,j)$ の値が $k$ の倍数となるペア $(i,j)$ の数は,$i,j$ がそれぞれ $k$ の倍数ということだから,$\lfloor N/k \rfloor \times \lfloor M/k \rfloor$ となる.
解法の $1$ つは包除原理する.
基本的には,答えに $2$ の ${\rm GCD}(i,j)$ が $2$ の倍数になるものの数乗をかけて,$3$ の ${\rm GCD}(i,j)$ が $3$ の倍数になるものの数乗をかけて,とやっていく.
ただし,${\rm GCD}(i,j)$ が $6$ の倍数となるものを考えると,それらは,既に,$2$ の倍数や $3$ の倍数を掛けるときに時に使用したので,掛け過ぎになるので包除原理が必要になる.
例えば,$\verb|arr[|k\verb|]|$ に,最初,$k$ を代入しておく.
そして,$GCD(i,j)$ が $k$ の倍数になる時の処理は,$\verb|arr[|k\verb|]|$ の個数乗を答えに掛け,$k$ の倍数 $x$ に対して,$\verb|arr[|x\verb|]|$ の値を $\verb|arr[|k\verb|]|$ で割っておけば良い.
この包除原理は想定解法ではないが,十分間に合う(以下のコード).
少し考えれば,複数の相異なる素因数を $1$ つずつ持つ場合は,$\verb|arr[|k\verb|]|$ の値は処理するときに $1$ となり,考えなくて良いことがわかる.
そこで,素数のべき乗を処理することを考えれば,異なる素因数をもつ場合は考える必要がないことがわかる.
よって,素数のべき乗 $p^k$ のみを考え,それらに対して,$p$ の $\lfloor N/p^k \rfloor \times \lfloor M/p^k \rfloor$ 乗をかけていけば良いことがわかる.

C++によるスパゲッティなソースコード

#include<bits/stdc++.h>
using namespace std;

#define REP(i,a,b) for(i=a;i<b;i++)
#define rep(i,n) REP(i,0,n)

#define mygc(c) (c)=getchar_unlocked()
#define mypc(c) putchar_unlocked(c)

#define ll long long
#define ull unsigned ll

void reader(int *x){int k,m=0;*x=0;for(;;){mygc(k);if(k=='-'){m=1;break;}if('0'<=k&&k<='9'){*x=k-'0';break;}}for(;;){mygc(k);if(k<'0'||k>'9')break;*x=(*x)*10+k-'0';}if(m)(*x)=-(*x);}
void reader(int *x, int *y){reader(x);reader(y);}
void writer(int x, char c){int i,sz=0,m=0;char buf[10];if(x<0)m=1,x=-x;while(x)buf[sz++]=x%10,x/=10;if(!sz)buf[sz++]=0;if(m)mypc('-');while(sz--)mypc(buf[sz]+'0');mypc(c);}

ull pw(ull a, ull b, ull m){ull r=1;while(b){if(b&1)r=r*a%m;b>>=1;a=a*a%m;}return r;}

void extended_euclid(ll x,ll y,ll *c,ll *a,ll *b){
  ll a0,a1,a2,b0,b1,b2,r0,r1,r2,q;
  r0=x; r1=y; a0=1; a1=0; b0=0; b1=1;
  while(r1>0){
    q=r0/r1; r2=r0%r1; a2=a0-q*a1; b2=b0-q*b1;
    r0=r1; r1=r2; a0=a1; a1=a2; b0=b1; b1=b2;
  }
  *c=r0; *a=a0; *b=b0;
}

ll get_inv(ll n, ll p){
  ll a,b,c;
  extended_euclid(n,p,&c,&a,&b);
  if(a<p) a+=p;
  return a%p;
}

#define M 1000000007
#define N 15100000

int mob[N];

int main(){
  int i, j, k;
  int X, Y;
  ll inv, res, tmp;

  rep(i,N) mob[i] = i;

  reader(&X,&Y);

  res = 1;
  REP(i,1,N) if(mob[i] != 1){
    inv = get_inv(mob[i], M);
    for(j=2*i;j<N;j+=i) mob[j] = (mob[j] * inv) % M;

    tmp = pw(mob[i], (ll)(X/i)*(Y/i), M);
    res = (res * tmp) % M;
  }

  writer((int)res, '\n');

  return 0;
}

Current time: 2017年09月26日02時01分30秒
Last modified: 2014年12月05日03時17分43秒 (by laycrs)
Tags: Competitive_Programming HackerRank HackerRank_w3
トップページに戻る

Logged in as: unknown user (not login)

ログイン: