题目分析
第一题
网上关于
我们知道,任何一个正整数 n n n 均可以用唯一素因数分解表示(百度百科),即 n = p 1 α 1 p 2 α 2 ⋯ p k α k n=p_1^{\alpha_1}p_2^{\alpha_2}\cdots p_k^{\alpha_k} n=p1α1p2α2⋯pkαk 这里 p 1 , ⋯ , p k p_1, \cdots, p_k p1,⋯,pk 均为素数且我们不妨设 p 1 < p 2 < ⋯ < p k p_1<p_2<\cdots <p_k p1<p2<⋯<pk。我们熟知, n n n 的正因数个数 d ( n ) = ∏ i = 1 k ( α i + 1 ) d(n)=\prod\limits_{i=1}^{k}(\alpha_i+1) d(n)=i=1∏k(αi+1),故我们相当于是要对 k k k 同样做出素因子分解。
调整一
我们先固定 α 1 , ⋯ , α k \alpha_1, \cdots, \alpha_k α1,⋯,αk,改动 p 1 , ⋯ , p k p_1, \cdots, p_k p1,⋯,pk. 我们设最小的 k k k 个素数依次为 2 = q 1 < q 2 < ⋯ < q k 2=q_1<q_2<\cdots <q_k 2=q1<q2<⋯<qk, 则显然有 p i ≥ q i ( ∀ 1 ≤ i ≤ k ) p_i\geq q_i(\forall 1\leq i\leq k) pi≥qi(∀1≤i≤k), 因此可以将 n = ∏ i = 1 k p i α i → 调整到 n ′ = ∏ i = 1 k q i α i n=\prod\limits_{i=1}^{k} p_i^{\alpha_i}\xrightarrow{\text{调整到}}n\prime = \prod\limits_{i=1}^{k}q_i^{\alpha_i} n=i=1∏kpiαi调整到n′=i=1∏kqiαi 并且 n ≥ n ′ n\geq n' n≥n′, 这样 n n n 会变小.
故以下就设 p 1 , ⋯ , p k p_1, \cdots, p_k p1,⋯,pk 就是从小到大的最小 k k k 个素数.
调整二
大的素因子幂应该尽可能小, 也即这里的 α 1 ≥ α 2 ≥ ⋯ ≥ α k \alpha_1\geq \alpha_2\geq \cdots \geq \alpha_k α1≥α2≥⋯≥αk.
调整三(有关 2 2 2 的幂)
else if(isTwopower(n) && n>=8)
{
for(int i=1;i<=100;i++)
{
divisor[i]--;
}
ans*=8;
int p=3;
for(int i=3;i<=100;i++)
{
while(!isPrime(p))
p++;
if(isPrime(p))
{
if ((divisor[i])==0)
break;
else
{
ans*=power(p,divisor[i]);
}
}
p++;
}
}
于是完整代码如下:
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <cmath>
using namespace std;
int divisor[101] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
bool isPrime(int p)
{
if (p == 0 || p == 1)
return false;
else
{
for (int i = 2; i < p; i++)
{
if (p % i == 0)
return false;
}
return true;
}
}
bool isTwopower(int n)
{
if(n==2)
return true;
else
{
if(n%2!=0)
return false;
else
{
return isTwopower(n/2);
}
}
}
long long power(int p, int a)
{
if(a==1)
return p;
else
{
return power(p,a-1)*p;
}
}
int cur=1;
void div(int n)
{
if(n==1)
divisor[cur]=1;
else
{
for(int i=n;i>=2;i--)
{
if(isPrime(i) && n%i==0)
{
divisor[cur]=i;
cur++;
div(n/i);
break;
}
}
}
}
int main()
{
long long n,ans=1;
cin >> n;
div(n);
if(n==1)
ans=1;
else if(isTwopower(n) && n>=8)
{
for(int i=1;i<=100;i++)
{
divisor[i]--;
}
ans*=8;
int p=3;
for(int i=3;i<=100;i++)
{
while(!isPrime(p))
p++;
if(isPrime(p))
{
if ((divisor[i])==0)
break;
else
{
ans*=power(p,divisor[i]);
}
}
p++;
}
}
else
{
for(int i=1;i<=100;i++)
{
divisor[i]--;
}
int p=2;
for(int i=1;i<=100;i++)
{
while(!isPrime(p))
p++;
if(isPrime(p))
{
if ((divisor[i])==0)
break;
else
{
ans*=power(p,divisor[i]);
}
}
p++;
}
}
cout<<ans;
return 0;
}
第二题
这题难度不大, 正常递归算法就能解决. (每次向下递归到 n → n p n\to \dfrac{n}{p} n→pn, 其中 p p p 为 n n n 的最小素因子)
注:之所以找最小素因子而不是最大真因子是因为通常情况下, 这样枚举的个数会大大减小,且减少了大数的运算.
import math
def is_prime(n):
for i in range(2,int(math.sqrt(n))+1):
if n%i==0:
return False
return True
def get_ans(n):
if n==1:
return 1
else:
for i in range(2,n+1):
if n%i==0:
return int(int(get_ans(n//i))+1)
else:
continue
n = int(input())
print(get_ans(n))
第三题
同样是采取递归的手法: 只需考虑末位为 0 0 0 或首位为 1 1 1 的递归即可. (这里最好把元音与辅音区分为 1 , 0 1,0 1,0 方便一些)
import string
def get_ans(ls):
if len(ls)==1:
return 1
else:
ret = 0
if ls[len(ls)-1]==0:
ret = ret + get_ans(ls[0:len(ls)-1])
if ls[0]==1:
ls.reverse()
ret = ret+get_ans(ls[0:len(ls)-1])
return ret
vowels = ['a','e','i','o','u']
alphabets = input()
eqnum = []
for i in range(len(alphabets)):
if alphabets[i] in vowels:
eqnum.append(1)
else:
eqnum.append(0)
print(get_ans(eqnum))
第四题
等比数列求和. 为了简化计算, 只需注意到 ⌊ x ⌋ + ⌊ x k ⌋ + ⌊ x k 2 ⌋ + ⋯ ≤ ∑ i = 0 + ∞ x k i = x ⋅ 1 1 − 1 k = k x k − 1 \lfloor x \rfloor +\lfloor \frac{x}{k} \rfloor +\lfloor \frac{x}{k^2} \rfloor +\cdots \le \sum_{i=0}^{+\infty}{\frac{x}{k^i}}=x\cdot \frac{1}{1-\frac{1}{k}}=\frac{kx}{k-1} ⌊x⌋+⌊kx⌋+⌊k2x⌋+⋯≤i=0∑+∞kix=x⋅1−k11=k−1kx 以及
⌊ x ⌋ + ⌊ x k ⌋ + ⌊ x k 2 ⌋ + ⋯ ≥ ⌊ x ⌋ + ⌊ x k ⌋ \lfloor x \rfloor +\lfloor \frac{x}{k} \rfloor +\lfloor \frac{x}{k^2} \rfloor +\cdots \ge \lfloor x \rfloor +\lfloor \frac{x}{k} \rfloor ⌊x⌋+⌊kx⌋+⌊k2x⌋+⋯≥⌊x⌋+⌊kx⌋
import sys
sys.setrecursionlimit(20000)
def get_ans(n,k):
if n==0:
return 0
else:
return (n+int(get_ans(n//k,k)))
n,k = map(int,input().split(' '))
res=0
if n==1:
res = 1
else:
low = int(n*(k-1)/k)-1
up = int(n*(k)/(k-1))+1
for i in range(low,up):
if get_ans(i,k)>=n:
res=i
break
print(res)
最终结果: 25 + 25 + 25 + 25 = 100 , rank = 3 25+25+25+25=100, \text{rank}=3 25+25+25+25=100,rank=3
建议(部分同上次)
- 本次比赛的编辑器并不是非常友好,例如调试中注释的快捷键
Ctrl + /
就无法使用,因此笔者在考试时实际使用了jupyter notebook
编辑器并复制进去(20 次的复制和切屏限制应该还算合理) - 最后希望官方能够在比赛结束后迅速给出题解,以供学习,这样才能完全达到比赛的最好效果。
- 比赛一开始系统就承受不住压力,等了将近两个小时才进去。希望下次能够尽量避免这种技术问题。
当然,也希望以后 CSDN 的编程竞赛能够越办越好!