LightOj 1045 Digits of Factorial
题意(好题)
给定一个数N,和进制k, 求N!在k进制下 位数的个数
思路
设进制为base,m为个数
N
!
=
b
a
s
e
m
N! = base^m
N!=basem,
m
m
m即 位数的个数
则
b
a
s
e
m
=
N
!
=
1
∗
2
∗
3
∗
4
∗
.
.
.
∗
(
n
−
1
)
∗
n
base^m = N! = 1 * 2 * 3 * 4 * ...* (n - 1) * n
basem=N!=1∗2∗3∗4∗...∗(n−1)∗n
两边同时取对数log
m
l
o
g
b
a
s
e
=
l
o
g
1
+
1
o
g
2
+
1
o
g
3
+
.
.
.
+
l
o
g
n
mlog^{base} = log1 + 1og2 + 1og3 + ..._+ logn
mlogbase=log1+1og2+1og3+...+logn
m
=
l
o
g
1
+
l
o
g
2
+
l
o
g
3
+
.
.
.
+
l
o
g
n
l
o
g
b
a
s
e
m = \frac{log1+log2+log3+...+logn}{log^{base}}
m=logbaselog1+log2+log3+...+logn
注意算的结果是下取整,则当结果m并不是恰好的数时,即存在小数的话,需要加
1
1
1
补充一下进制转换:
120转换成八进制
120
%
8
=
0
120 \% 8 = 0
120%8=0,
120
/
8
=
15
120 / 8 = 15
120/8=15
15
%
8
=
7
15 \% 8 = 7
15%8=7,
15
/
8
=
1
15 / 8 = 1
15/8=1
1
%
8
=
1
1 \% 8 = 1
1%8=1,
1
/
8
=
0
1 / 8 = 0
1/8=0
代码
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 1000010;
double s[N];
void init() {
s[0] = s[1] = 0;
for (int i = 2; i < N; i ++)
s[i] = s[i - 1] + log((double)i);
}
int main() {
init();
int T;
int id = 0;
scanf("%d", &T);
while(T --) {
int n, base;
scanf("%d%d", &n, &base);
if(!n) {
printf("Case %d: %d\n", ++id, 1);
continue;
}
double c = s[n];
double m1 = c / (log((double)base));
int m2 = c / (log((double)base));
if(m2 != (int)ceil(m1)) {
m2 ++;
}
printf("Case %d: %d\n", ++ id, m2);
}
return 0;
}
LOJ1090 Trailing Zeroes (II)
题意
输出结果末尾0的个数
思路
找质因数分解最终2和5的幂个数就行,2和5的幂 取最小值
C
n
r
=
n
!
r
!
(
n
−
r
)
!
C_n^r = \frac{n!}{r!(n-r)!}
Cnr=r!(n−r)!n!
然后阶乘分解+质因子分解就行
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
LL T, n, r, p, q;
LL get_num1(LL n, int x) {
LL s = 0;
for (LL j = n; j; j /= x) {
s += j / x;
}
return s;
}
LL get_num2(LL n, LL x) {
LL s = 0;
while(n % x == 0) {
s++;
n /= x;
}
return s;
}
int main() {
int id = 0;
cin >> T;
while(T --) {
cin >> n >> r >> p >> q;
int num_2 = get_num1(n, 2);
int num_5 = get_num1(n, 5);
num_2 -= get_num1(r, 2);
num_5 -= get_num1(r, 5);
num_2 -= get_num1((n-r), 2);
num_5 -= get_num1((n-r), 5);
num_2 += (LL)get_num2(p, 2) * q;
num_5 += (LL)get_num2(p, 5) * q;
LL ans;
if(num_2 > num_5) {
ans = num_5;
}
else
ans = num_2;
printf("Case %d: %lld\n", ++id, ans);
}
return 0;
}
LightOJ - 1278 Sum of Consecutive Integers
思路
n
=
a
1
+
a
2
+
a
3
+
.
.
.
+
a
m
n = a_1 + a_2 + a_3 + ...+a_m
n=a1+a2+a3+...+am
n
=
m
∗
a
1
+
(
a
1
+
m
−
1
)
2
n = m * \frac{a_1+(a_1+m-1)}{2}
n=m∗2a1+(a1+m−1)
a
1
=
n
m
−
m
−
1
2
a_1=\frac{n}{m}-\frac{m-1}{2}
a1=mn−2m−1
可知
m
,
n
,
a
1
m,n,a_1
m,n,a1均为整数,则从
m
−
1
2
\frac{m-1}{2}
2m−1 看出
m
m
m一定 是奇数
从
n
m
\frac{n}{m}
mn看出
m
m
m是
n
n
n的因子, 则
m
m
m是
n
n
n的奇因子
因此,求出 n n n的所有奇因子个数即可
注意:最后要减去一,因为 m m m不能为1
代码
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10000010;
int primes[N];
bool st[N];
int cnt;
void get_primes() {
for (int i = 2; i < N; i ++) {
if(!st[i])
primes[cnt++] = i;
for (int j = 0; primes[j] * i < N; j ++) {
st[primes[j] * i] = true;
if(i % primes[j] == 0)
break;
}
}
}
int main() {
get_primes();
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
int id = 0;
int T;
scanf("%d", &T);
while(T --) {
long long n;
scanf("%lld", &n);
while(n % 2 == 0)
n /= 2;
long long ans = 1;
for (int i = 0; i < cnt && primes[i] * primes[i] <= n; i ++) {
int p = primes[i];
if(n % p == 0) {
int s = 0;
while(n % p == 0) {
s++;
n /= p;
}
ans = (long long)ans * (s + 1);
}
}
if(n != 1)
ans *= 2;
printf("Case %d: %d\n", ++id, ans - 1);
}
return 0;
}
LightOJ - 1289 LCM from 1 to n
题意
求LCM(1,2,3…,n)
思路
最大公倍数无非就是 p 1 m a x ( c 1 ) p 2 m a x ( c 2 ) . . . p n m a x ( c n ) p_1^{max(c1)}p_2^{max(c2)}...p_n^{max(c_n)} p1max(c1)p2max(c2)...pnmax(cn)
步骤:
- 筛质数(st用二进制存),预处理前缀和(乘法)
- 分解质因数, 只需枚举到根号n (大于根号n的幂都是1), 求 m a x ( c 1 ) max(c_1) max(c1)
- 相乘
注意
- 取模 2 3 2 2^32 232, 用unsigned int 就行
- 1~n的质数个数为 n ln n \frac{n}{\ln n} lnnn
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e8 + 5, M = 5800000;
// 因为st只需0,1状态, 可以用位图即二进制位存储状态, 否则超内存
bitset<N> st;
int primes[M];
int cnt;
unsigned int sum[N];
void get_primes() {
for (int i = 2; i < N; i ++) {
if(!st[i])
primes[cnt++] = i;
for (int j = 0; primes[j] * i < N; j ++) {
st[primes[j] * i] = 1;
if(i % primes[j] == 0)
break;
}
}
// 预处理前缀乘
sum[0] = 2;
for (int i = 1; i < cnt; i ++)
sum[i] = sum[i - 1] * primes[i];
}
unsigned int qmi(int a, int b) {
unsigned int ans = 1;
while(b) {
if(b & 1)
ans *= a;
a *= a;
b >>= 1;
}
return ans;
}
int main() {
get_primes();
int T;
scanf("%d", &T);
int id = 0;
while(T --) {
int n;
scanf("%d", &n);
// 找第一个大于n的素数, 然后减一, 就是小于n的最大素数了
int pos = upper_bound(primes, primes + cnt, n) - primes;
pos -= 1;
unsigned int ans = sum[pos];
for (int i = 0; i < cnt && primes[i] * primes[i] <= n; i ++) {
int s = 0;
int temp = n;
while(temp / primes[i]) {
s++;
temp /= primes[i];
}
s--; // 前缀和已经乘了一次, 要减去一次
ans = ans * qmi(primes[i], s);
}
printf("Case %d: %lld\n", ++id, ans);
}
return 0;
}
LightOj1340 Story of Tomisu Ghost
题意
问n!在b进制下至少有t个后缀零,求最大的b。
思路
由转换进制,辗除法可知,看质因子最大的幂即可
若
p
k
c
k
p_k^{c_k}
pkck 的
c
k
>
=
t
c_k >= t
ck>=t, 则该
p
k
p_k
pk满足,且
c
k
c_k
ck很大的话,可以继续扩大b进制,即答案为
p
i
s
/
t
p_i^{s/t}
pis/t进制
代码(转Lweleth)
#include<bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 1e5+2000;
const int mod = 10000019;
LL pri[N];
int c = 0;
bool vis[N];
void prime()
{
for(int i = 2; i < N; i++)
{
if(!vis[i])
{
for(int j = i + i; j < N; j+= i)
{
if(!vis[j])
vis[j] = 1;
}
pri[c++] = i;
}
}
}
LL fpow(LL a, LL n)
{
LL r = 1;
while(n > 0)
{
if(n & 1)
r = r * a % mod;
a = a * a % mod;
n >>= 1;
}
return r;
}
int main()
{
prime();
int T;
int cnt = 0;
cin >> T;
while(T--)
{
LL n;
LL r;
cin >> n >> r;
LL ans = 1;
for(int i = 0; i < c && pri[i] <= n; i++)
{
LL t = n;
LL ct = 0;
while(t)
{
ct += t / pri[i];
t /= pri[i];
}
if(ct >= r)
ans = ans * fpow(pri[i], ct/r) % mod;
if(ct < r)
break;
}
if(ans == 1)
printf("Case %d: -1\n", ++cnt);
else
printf("Case %d: %d\n", ++cnt, ans);
}
return 0;
}