1.连续因子
题目链接:这里
题意:一个正整数 N 的因子中可能存在若干连续的数字。例如 630 可以分解为 3×5×6×7,其中 5、6、7 就是 3 个连续的数字。给定任一正整数 N,要求编写程序求出最长连续因子的个数,并输出最小的连续因子序列。
思路:题意是要找到连续的最小的因子,并且这些因子的乘积任是这个数的因子,那么我们第一步要找到这个数的所有的因子,我们是通过for(int i = 2; i <= sqrt(n) + 1; i++)来找因子的,为什么要+1,虽然连续因子肯定不会以sqrt(n)+1打头,因为如果是素数,那只有一个因子即本身。如果不是素数,那么肯定有一个因子在小于等于sqrt(n),如果最长序列为1的话也是在2~sqrt(n)之中,不可能是sqrt(n)+1;如果最长序列大于1的话,更不可能是以sqrt(n)+1打头的,因为sqrt(n)+1乘以下一个因子必大于n。但sqrt(n)+1是有可能包括在前一个因子的序列中,就好比输入6的这种情况。所以sqrt(n)+1还是要考虑在内的,它后面的因子就不用考虑了,肯定是不可能的,因为不会有以它们开始的序列的。借鉴
看代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
int n; cin >> n;
int m = sqrt(n);
int s[m], t = 0;
for (int i = 2; i <= m + 1; i++)
if (n % i == 0) s[t ++] = i;
if (t == 0) cout << '1' << endl << n << endl;///素数的情况
else if (t == 1) cout << '1' << endl << s[0] << endl;///只有一个因子的情况
else
{
int len = 0, sum = 0, mlen = 0, pos = 0;
for (int i = 0; i < t - 1; i ++)
{
sum = s[i], len = 1;
for (int j = i; j < t - 1; j ++)
{
if (s[j + 1] - s[j] == 1 && n % (sum * s[j + 1]) == 0) {sum *= s[j + 1]; len ++;}
else break;
}
if (len > mlen) {mlen = len; pos = i;}
}
cout << mlen << endl;
cout << s[pos];
for (int i = pos + 1; i < pos + mlen; i++)
cout << '*' << s[i];
cout << endl;
}
return 0;
}
2.N个数求和
链接
题意:是求N个数字的和。麻烦的是,这些数字是以有理数分子/分母的形式给出的,你输出的和也必须是有理数的形式。输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分,其中分数部分写成分子/分母,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。
思路:这个题思路很简单,就是把分母通分,然后通分后把分子求出来,在约分,然后按照要求输出即可,最开始的时候我害怕爆longlong,在分子累加的时候就进行了约分,但是还是只有18分,后面才发现漏了一种情况,就是当你的结果类似于0/1这种分子是0,分母是其他任何非零数字的时候,这种情况下答案都是0。
AC代码:
#include <bits/stdc++.h>
#define int long long
#define x first
#define y second
using namespace std;
int n;
pair<int, int> q[110];
signed main()
{
bool flag = true;
cin >> n;
for (int i = 1; i <= n; i++) scanf("%lld/%lld", &q[i].x, &q[i].y);
int fm = q[1].y, fz = q[1].x;
for (int i = 2; i <= n; i++)
{
int gcd = fm * q[i].y / __gcd(q[i].y, fm);
fz = (fz * (gcd / fm) + q[i].x * (gcd / q[i].y));
fm = gcd;
int gcd_1 = __gcd(fz, fm);
fz /= gcd_1, fm /= gcd_1;
}
int gcd = __gcd(fz, fm);
fm /= gcd, fz /= gcd;
int res_1 = fz / fm, res_2 = fz - res_1 * fm;
if (res_1 == 0 && res_2 == 0) {puts("0"); return 0;}
if (res_1 == 0) cout << res_2 << '/' << fm << endl;
else if (res_2 == 0) cout << res_1 << endl;
else cout << res_1 << ' ' << res_2 << '/' << fm << endl;
return 0;
}
3.功夫传人
题意:假设家谱中的每个人只有1位师傅(除了祖师爷没有师傅);每位师傅可以带很多徒弟;并且假设辈分严格有序,即祖师爷这门武功的每个第i代传人只能在第i-1代传人中拜1个师傅。我们假设已知祖师爷的功力值为Z,每向下传承一代,就会减弱r%,除非某一代弟子得道。现给出师门谱系关系,要求你算出所有得道者的功力总值。
思路:我们可以用一个二维数组来表示某个节点的下一代,但是每个节点我们不知道到底有多少个下一代,那么我们可以用一个二维vector来存储,然后直接搜索就可以。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n;
double z, r, ans;
vector<int> chi[N];
double val[N];
void dfs(int id, double w)
{
if (val[id]) ans = ans + w * val[id];
else
{
for (int i = 0; i < chi[id].size(); i ++)
dfs(chi[id][i], w * r);
}
}
int main()
{
memset(val, 0, sizeof val);
ans = 0;
scanf("%d %lf %lf", &n, &z, &r);
r = (100 - r) / 100;
for (int i = 0; i < n; i++)
{
int k; scanf("%d", &k);
if (k == 0) scanf("%lf", &val[i]);
else
{
for (int j = 0; j < k; j ++)
{
int x; scanf("%d", &x);
chi[i].push_back(x);
}
}
}
dfs(0, z);
printf("%d\n", (int)ans);
return 0;
}
本文介绍了PTA平台上的三道算法题目,包括寻找正整数的最长连续因子个数、计算有理数序列的和以及解决功夫传人的功力计算问题。分别解析了解题思路并提供了关键代码片段。
2107






