長さ $N+1$ の正整数列 $\{X_k\}_{k=0}^N$ が与えられる(実際には乱数生成方法と種が与えられる).
その中から,$K$ 個の要素を選び,その積を $B$ 進数で表した時,末尾の $0$ の個数を最小化したい.
うまく $K$ 個の整数を選んだ時の,最小値を求める問題.
$B = p_1^{m_1} p_2^{m_2} \cdots p_f^{m_f}$ と素因数分解する.
$z$ が持つ素因数 $p_k$ の個数を $s_k$ とする($z$ は $p_k^{s_k}$ で割り切れる)とすると,$z$ を $B$ 進数で書いた時の末尾の $0$ の数は $\displaystyle \min_k \lfloor m_k/s_k\rfloor$ となる.
これを最小化したいのだから,ボトルネックとなる $k$ を全て試せば良い.
つまり,$\{X_k\}_{k=0}^N$ の要素のうち,$p_k$ で割り切れる回数が少ない方から $K$ 個を選ぶというのを全ての $k$ に対して試す.
#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 ll long long
#define ull unsigned ll
#define INF 1000000000
int Q;
int seed, N, K, B;
int X[100000];
int Y[100000];
int p[20], pn[20], ps;
int main(){
int i, j, k;
int res;
scanf("%d",&Q);
while(Q--){
scanf("%d%d%d%d",&seed,&N,&K,&B);
N++;
X[0] = seed;
REP(i,1,N) X[i] = 1 + (((ll)X[i-1]*X[i-1] + (ll)X[i-1]*12345) % 100000009);
ps = 0;
for(i=2;i<=B;i++){
if(B%i==0){
p[ps] = i;
pn[ps] = 0;
while(B%i==0) pn[ps]++, B/=i;
ps++;
}
}
res = INF;
rep(k,ps){
rep(i,N){
Y[i] = 0;
j = X[i];
while(j%p[k]==0) j/=p[k], Y[i]++;
}
sort(Y, Y+N);
j = 0;
rep(i,K) j += Y[i];
res = min(res, j/pn[k]);
}
printf("%d\n",res);
}
return 0;
}
Current time: 2024年03月29日18時28分31秒
Last modified: 2014年11月06日13時04分11秒 (by laycrs)
Tags: Competitive_Programming yukicoder
トップページに戻る
Logged in as: unknown user (not login)