题意:给定两整数m,n(m < 5 000, n < 10 000),求一最大k,使得m^k能被 n! 整除.
解题思路:
抱着试一试的心态AC了。。。。。。
想到 m^k 能被 n! 整除,那么 m 任意素数因子 p 的k次方都能被 n! 整除,因此只要保存 n!中各个素因子的个数即可,
然后枚举 m 的素数因子, 求出最小的倍数就是答案,若素数因子 p 在 n! 中出现的次数小于 m中的,那么就是 “Impossible to divide”
之所以不敢写就是初始化的时候枚举1~N的所有素数因子时间复杂度为O(N^2),没想到数据挺水的,后来上网看了下,都大致是这个解法。。。。。。
代码:
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
#include <list>
using namespace std;
const int N = 1e4;
int dp[N+10][N+10];
struct node
{
int prime,cnt; //素数,素数出现的次数
node(int pp,int cc): prime(pp), cnt(cc) {}
node() {}
};
void init()
{
for(int i = 2;i <= N;i++) { // 枚举 i阶乘
int m = sqrt(i+0.5), t = i;
for(int k = 2;k <= i;k++) dp[i][k] = dp[i-1][k]; //将前面一个数的阶乘因子转移下来
for(int j = 2;j <= m ;j++) { //当前i 的素数因子分解
while(t % j == 0) t /= j, dp[i][j] ++;
}
if(t > 1) dp[i][t] = dp[i-1][t] + 1;
}
}
void OnlyEquation(int n, vector<node>& vec) //唯一分解定理
{
int m = sqrt(n+0.5);
for(int i = 2;i <= m;i++) {
if(n % i == 0) {
int t = 1;
n /= i;
while(n % i == 0) n /= i,t++;
vec.push_back(node(i,t) );
}
}
if(n > 1) vec.push_back(node (n,1));
}
int main()
{
int T, cas = 1, n ,m;
init();
cin >> T;
while(T--) {
scanf("%d%d",&m,&n);
vector<node> vec;
OnlyEquation(m, vec);
int mx = 9999999;
int flag = 1;
for(int i = 0,k = vec.size();i < k;i++) {
node p = vec[i];
if(dp[n][p.prime] < p.cnt) { //n!阶乘中p.prime的因子个数小于m中的
flag = 0;
break;
}
int t = dp[n][p.prime] / p.cnt; //倍数关系,向下取整
if(t < mx) mx = t; //所有因子倍数中取最小的
}
printf("Case %d:\n",cas++);
if(!flag) {
printf("Impossible to divide\n");
continue;
}
printf("%d\n", mx);
}
return 0;
}