2019.1.5 测试
文章目录
First Of All
这次考试其实总体来看还不是很难
然而做得并不好 只有第三题A了
主要是不会打高精&理解错了题意 (题意都读不懂还做什么题啊)
A 整数划分
Description
读入一个正整数n。要求将n写成若干个正整数之和,并且使这些正整数的乘积最
大。例如,n=13,则当n表示为4+3+3+3(或2+2+3+3+3)时,乘积=108为最大。
Input
一个整数,n。
Output
第1行输出一个整数,为最大乘积的位数。第2行输出最大乘积的前100位,如果
不足100位,则按实际位数输出最大乘积。(提示:在给定的范围内,最大乘积的
位数不超过5000位)。
Sample Input
13
Sample Output
3
108
分析
看到这道题的第一反应:并没有任何反应
5000位 高精度??? 均值不等式???(分成2个数) 算了 然后跳过
思路
首先比较容易想到的一个数学结论(并不会严谨证明 然而正确性显然)
打表找规律可以发现:
要使乘积最大,我们应该把它分成尽量多的3和2相乘 由于3和2一个是奇数,一个是偶数,所以这个数最后一定能完全地分成3和2的和
我们就把它一直分3出来 直到它小于等于4 我们就会发现一些情况:
原因:
由于4=2+2时最大 当这个数还剩下4的时候就不能再分3出来 因为4=1+3的情况并不够优秀 所以这种情况直接乘上n即可
还剩下3的时候:直接乘
还剩下2:直接乘
还剩下1:不存在 如果还剩下1,那它可以去找之前的一个2或者3 结合 然后使结果更优秀 事实上,由于我们之前一直都是分的3出来,唯一可能会出现1的情况就是最开始讨论的剩下4的情况,而它已经被我们解决掉了
还剩下0:这是一种什么奇怪的现象 由于我们每次-3 而最后的判断是小于等于4 所以不存在
结论:当这个数小于等于4的时候直接跳出循环把它自己乘上去就可以了
高精度部分
其实高精度乘法还是比较容易理解的 代码都比较好看 大概想一下平时手算竖式乘法的时候就可以理解了
主要是我实在是太久没有写过了
上一次写的高精度还是
在n年之前的生日qwq (我居然还会在生日写题)
代码
#include<cstdio>
#include<vector>
using namespace std;
#define MAXN 5005
int a[MAXN];
int n;
int main()
{
int l=1,d=0,i;
a[1]=1;
scanf("%d",&n);
while(n>4)
{
n-=3;
for(i=1;i<=l;i++)
{
a[i]=a[i]*3+d;
d=a[i]/10;//给下一位进的位
a[i]=a[i]%10;
}
while(d>0)
{
a[i]=d%10;
d=d/10;
i++;
}
l=i-1;
}
for(i=1;i<=l;i++)
{
a[i]=a[i]*n+d;
d=a[i]/10;
a[i]=a[i]%10;
}
while(d>0)
{
a[i]=d%10;
d=d/10;
i++;
}
l=i-1;
printf("%d\n",l);
for(int i=l;i>=max(1,l-100+1);i--)
printf("%d",a[i]);
return 0;
}
B 地震
Description
(校内OJ)
农夫John的农场遭受了一场地震。有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用。
FJ的农场有P个牛棚,编号1…P, C条双向路经连接这些牛棚,编号为1. . C。路经i连接牛棚ai和bi,路经可能连接ai到它自己,两个牛棚之间可能有多条路经。农庄在编号为1的牛棚.,
N头在不同牛棚的牛通过手机短信reroortj告诉FJ它们的牛棚(reportj)没有损坏,但是它们无法通过路经和没有损坏的牛棚回到到农场。当FJ接到所有短信之后,找出最小的不可能回到农庄的牛榭数目。这个数目包括损坏的牛棚。
讨论一下题意
果然语文还是太烂了
还想吐槽一下题目描述 有点绕 还有错别字qwq
我之前的理解:有N头奶牛的牛棚已知没有破坏,现在它们要回去,但是不能经过牛棚损坏的地方,请问这些奶牛最少有多少头奶牛不能回去(加上已经损坏的牛棚数目)
正确的理解应该是这样的 :
农夫John的农场遭受了一场地震。有一些牛棚遭到了损坏,但幸运地,所有牛棚间的路经都还能使用。
一共有P个牛棚,由C条双向路连接一条路可能连接相同的牛棚.农庄在编号为1的牛棚.
奶牛不能经过损坏的牛棚,并且只能沿道路行走。N头在不同牛棚的牛通过手机短信reroortj告诉FJ它们的牛棚(reportj)没有损坏,但是它们无法回到农场。找出最小的不可能回到农庄的牛棚数目。这个数目包括损坏的牛棚。
Input
第1行:三个空格分开的数:P, C,和N
第2 …C+1行:每行两个空格分开的数:ai和bi
第C+2 …C+N+1行:每行一个数:reroortj
Output
第1行:一个数,最少不能回到农庄的牛的数目(包括损坏的牛棚)
Sample Input
4 3 1
1 2
2 3
3 4
3
Sample Output
3
Hint
【数据范围】
1 ≤ P ≤ 30000,1 ≤ C ≤ 100000,1 ≤ N ≤ P,2 ≤ reportj ≤ P
分析
首先,样例没什么好说了的吧
3不能回去,那么一定是2损坏了 而2一旦损坏,2,3,4都不能回去
推广一下 一个牛棚不能到达1,一定是它去1的每一条路上都至少有一个点损坏
那么我们现在的问题就是 要让这些路径上的哪个点损坏 才能使更少的牛棚无法到达1
而显而易见的是:
那个损坏的点,离当前这个无法到达的点越远,就越有可能妨碍到更多的点
比如说这些比较极端的情况:
更极端的情况:
有了这个结论,我们就可以把那些被困住的点的邻接点视为破坏,然后从节点1开始搜索,搜到的点就是可以到达1的点,然后减去就可以了
C 最长上升子序列
Description
给出一个长度为N的整数序列,求出包含它的第K个元素的最长上升子序列。
Input
第一行两个整数N, K
第二行N个整数
Output
如题目所说的序列长度。
Sample Input
8 6
65 158 170 299 300 155 207 389
Sample Output
4
Hint
【数据范围】
0 < N ≤ 200000,0 < K ≤ N
分析
这道题比较简单
由于范围较大 我们可以考虑nlogn 的模板 (超链接)
于是问题开始变得简单起来,由于要保证第k个数存在 我们就将整个数列劈成两部分 求两个LIS 然后再夹上k 合起来
但是要注意的是:
左边那个LIS的最后面的那个数要比第k个数小,而右边的LIS的第一个数则要比它大(可以类比判断分段函数的单调性来理解)
(这个时候用nlogn算法的优势也体现出来了,可以更加方便地进行这项操作)
同时也要注意在进行右边的LIS更新时要先判断那个数大于第k个数