DISCO presents ディスカバリーチャンネル コードコンテスト2016 予選 C問題 - ロト2

Source

DISCO presents ディスカバリーチャンネル コードコンテスト2016 予選
問題文

問題概要

正整数からなる $N$ 要素の数列 $\{A_i\}_{i=1}^N$ が与えられる.
数列の中から $2$ つの要素を取り出して,その積が $K$ の倍数となるのは何通りあるかを求める問題.

解法

整数 $n$ が $K$ の倍数であるというのは,全ての素数について,素因数分解した時に $n$ に含まれる個数は $K$ に含まれる個数以上である,というのと同値.
よって,$K$ がもつ素因数以上のものは考えても考えなくても一緒なので,$A_i := \mathop{\mathrm{GCD}}(A_i,K)$ と置き直しておく.
そうすると,$A_i$ の値は $K$ の約数しかありえなくて,約数の数はそんなに多くはならないので,同じ値の $A_k$ はまとめて処理することができる.
後は,愚直に全パターンの組み合わせを調べれば良い.
よって,$K$ の約数の数を $d(K)$ と書くと,時間計算量は $O(N \log(\max(A_i,K)) + d(K)^2)$ 程度で,$d(K)$ の最大値は $1400$ ぐらいなので十分間に合う.

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

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);}
template <class T, class S> void reader(T *x, S *y){reader(x);reader(y);}
void writer(ll x, char c){int s=0,m=0;char f[20];if(x<0)m=1,x=-x;while(x)f[s++]=x%10,x/=10;if(!s)f[s++]=0;if(m)mypc('-');while(s--)mypc(f[s]+'0');mypc(c);}
template<class T> void writerLn(T x){writer(x,'\n');}
char memarr[17000000]; void *mem = memarr;

template<class T1, class T2> void sort(int N, T1 a[], T2 b[], void *mem){int i;pair<T1,T2> *r=(pair<T1, T2>*)mem;rep(i,N)r[i].first=a[i],r[i].second=b[i];sort(r,r+N);rep(i,N)a[i]=r[i].first,b[i]=r[i].second;}
template<class T, class S> void unique(T arr[], S val[], int &sz, void *mem, int sorted=0){int i,k=0;if(!sorted)sort(sz,arr,val,mem);rep(i,sz)if(!k||arr[k-1]!=arr[i])arr[k]=arr[i],val[k++]=val[i];else val[k-1] += val[i];sz=k;}
template<class T> T GCD(T a,T b){T r; while(a)r=b,b=a,a=r%a; return b;}

int N, K;
int A[200000], B[200000];

int main(){
  int i, j;
  ll res = 0;

  reader(&N,&K);
  rep(i,N) reader(A+i);
  rep(i,N) A[i] = GCD(A[i], K);
  rep(i,N) B[i] = 1;
  unique(A, B, N, mem);

  rep(i,N){
    if((ll)A[i] * A[i] % K == 0){
      res += (ll)B[i] * (B[i]-1) / 2;
    }
  }
  rep(i,N) REP(j,i+1,N){
    if((ll)A[i]*A[j] % K == 0){
      res += (ll)B[i] * B[j];
    }
  }

  writerLn(res);

  return 0;
}

Current time: 2017年09月25日07時58分56秒
Last modified: 2016年11月06日16時21分46秒 (by laycrs)
Tags: Competitive_Programming AtCoder ddcc2016-qual
トップページに戻る

Logged in as: unknown user (not login)

ログイン: