n!%k^i==0
n!%k^i==0
TimeLimit:5000MS MemoryLimit:65536KB
64-bit integer IO format:%I64d
Problem Description
给你n和k,求最大的i 使得n!%k^i==0
Input
第一行是一个t表测试数据的组数
每组测试数据包含2个数n和k
1 <= T <= 500
1 <= K <= 1 000 000 000 000 00
1 <= N <= 1 000 000 000 000 000 000
每组测试数据包含2个数n和k
1 <= T <= 500
1 <= K <= 1 000 000 000 000 00
1 <= N <= 1 000 000 000 000 000 000
Output
每个测试数据先输出case数,然后输出答案。如果答案超过9 223 372 036 854 775 807 则输出“inf”
SampleInput
2 2 2 10 10
SampleOutput
Case 1: 1 Case 2: 2
被这题坑了好几次。
注意点:
1、 由于 k 的 开方有一千万。 就是说, 得打表一千万以内的所有素数, 才60+万而已。在500次循环中, oj上有明显的用时。起码没打表的时候, 超时了
2、 int 整型相乘, 注意可能超出 int 范围, 超出范围, 是不会自动转换成 long long 型的。 所以得注意 类型 的 显式转换。
计算 n! 中 有几个 i 相乘, 有 递推 可求。详见代码。
代码:
View Code
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int all = (1e7)+1000; bool test[ all ]; int con[ 700000 ], spot; ll t, numk, numn, tmpk, tmpn, cnt, k, n; void make() { for( int i=2; i*i <= all; ++ i ){ if( test[ i*i ] == true ){ continue; } for( int j=i; i*j <= all; ++ j ){ test[ i*j ] = true; } } for( int i=2; i <= all; ++ i ){ if( ! test[ i ] ){ con[ spot ++ ] = i; } } } int main(void) { spot = 0; make(); scanf( "%d", &t ); for( int i=1; i <= t; ++ i ){ scanf( "%I64d%I64d", &n, &k ); printf( "Case %d: ", i ); cnt = 9223372036854775807; if( k == 1 ){ puts( "inf" ); continue; } // 利用 k 的缩小, 可以缩短计算量 // 注意 int 类型的范围, 这里需要进行 显式转换 成 long long 类型, 否则会溢出 for( int j=0; (ll)con[j]*con[j] <= k; ++ j ){ if( k % con[j] == 0 ){ numk = 0; while( k % con[j] == 0 ){ k /= con[j]; ++ numk; } // 计算 n!中 含有几个 con[j] 相乘 numn = 0; tmpn = n; while( tmpn ){ tmpn /= con[j]; numn += tmpn; } cnt = cnt < numn/numk ? cnt : numn/numk; } } // 存在当 con[j]*con[j] > k, 而又 k != 1 时, 所需要的计算 if( k != 1 ){ numn = 0; tmpn = n; while( tmpn ){ tmpn /= k; numn += tmpn; } cnt = cnt < numn ? cnt : numn; } printf( "%I64d\n", cnt ); } return 0; }