C2第六周练习

 

事开始多了起来,如果必要的话这个坑可能会放一放,毕竟开了一个练习回顾,一直开放到明年,没有时间限制要求的话会舒服很多。

另外从这次开始可能有些题就懒得贴代码了= =

PS:其实写这篇博客的时候我还是有一个点没过,不过我也不知道该怎么测试= =

PSS:过了,还是输入的问题= =

组合

【问题描述】
求n个自然数(1-n)的所有m-组合,即C(n,m)的所有不可重复的组合形式。
【输入形式】
标准输入。输入只有一行,包括两个整数n和m,其中0<n<=20,0<m<=n,二者之间以一个空白符分隔。 输入内容可以保证在算法得当情况下,规定时间内可以完成。
【输出形式】
在标准输出上输出有若干行,每一行都是符合题意的一种排列形式,每个元素间用一个空格分隔,并按升序排列。
【输入样例】
3 2
【输出样例】
1 2 
1 3 
2 3
【时间限制】
2s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为zuhe.c。

这回懒得贴链接了,直接翻前面全排列那个博客就是了。

Antiprime

【问题描述】
设n是一个自然数,如果对所有的自然数x(x<n),x的约数个数都少于n的约数个数,则称n是一个Antiprime数。如:1, 2, 4, 6, 12, 24。
试计算不大于n的最大Antiprime数。
【输入形式】
输入文件为当前目录下的antiprime.in。 该文件只有一个整数n,(1≤n≤20 000 000 00)。
【输出形式】
输出文件为当前目录下的antiprime.out。 该文件只包含一个整数,即不大于n的最大Antiprime数。
【输入样例】
100
【输出样例】
60
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为antiprime.c。

个人认为这次最难的题,因为写的时候根本没有思路。最终还是看别人的思路写的这题。。。我好菜哦

思路是这样的,有个叫唯一分解定理的,任何一个大于1的数都可以分解为许多质数的乘积,并且根据质因数的个数可以算出约数的个数,公式为:n = 2^{t1} * 3 ^{t2} * 5^{t3}....。n的约数个数为(t1+1)*(t2+1)*……

(这些数论的知识完全不了解了啊)

那么对于这题我们就可以还是DFS爆搜+回溯来做。需要注意t1>=t2>=t3……。因为显然质因子越小其对应的约数越多,当然是可以证明的不过我也不会。所以直接枚举可能出现的质因子的个数即可。

那么递归调用时我们需要记录以下参数,当前数字,当前数字的因数,当前数字可能出现的最大次数以及枚举到第几个质数。代码如下:

#include<stdio.h>

long long prime[11] = {0,2,3,5,7,11,13,17,19,23,100000}; 
long long n, maxsum = 1, anti = 1;

void antiprime(long long curnum, long long tsum, long long k, long long limit)
{
	printf("%lld\n",curnum);
	if (tsum > maxsum)
	{
		maxsum = tsum;
		anti = curnum;
	}
	if (tsum == maxsum && curnum < anti)
		anti = curnum;

	long long i;
	for (i = 1; i <= limit; i++)
	{
		curnum *= prime[k];
		if (curnum > n)	return;
		antiprime(curnum, tsum*(i + 1), k + 1, i);
	}
}

int main()
{
	freopen("antiprime.in", "r", stdin);
	freopen("antiprime.out", "w", stdout);
	scanf("%lld", &n);
	antiprime(1, 1, 1, 10);
	printf("%lld", anti);
	return 0;
}

之所以到23,是因为2*3*5*……*23已经大于给定的n了。后面那个100000是个哨兵。

先枚举只有1个2的情况,然后对于后面的数字递归调用。后面数字出现的次数不超过1.

再枚举有2个2的情况,……以此类推。

当然我这个代码在网上随处都能找到,因为我的思路就是看他们的。= =

字母频度

【问题描述】
统计文件中各字母的出现次数以及所有字母出现次数的总和。同一字母大小写的出现次数合并计算。
【输入形式】
输入文件为freq.in,文件最大长度不超过2000000个字符。
【输出形式】
输出文件为freq.out 输出包括两行,第一行输出在文件中出现次数最多的前10 位字母及其出现次数(从大到小排序)。
出现次数相同的字母按字母顺序排列。字母与出现次数连续输出,后接一空格。
如有并列第10的情况,即第11项与之后若干项的值与第10项相同,则输出所有的并列项。
 第二行输出所有字母出现的总和。
【输入样例】
Iraqi leaders attempted Thursday to close the widening sectarian divide in the wake 
of widespread reprisals by Shiite Muslims against Sunnis after the bombing of a Shiite shrine. 
Iraqi and U.S. officials called for calm,
but a powerful Sunni Arab political bloc said it is boycotting national unity talks.
A curfew was imposed Thursday evening in Baghdad and three surrounding provinces,
which could stir even more controversy because it will remain in effect through Friday's noon Muslim prayers
 -- the most sacred prayers of the week for followers.
【输出样例】
e45 i45 a38 s36 r33 t31 n29 o28 d20 l20 
453 
(表示出现e 45次,i 45次...总计字母453)
【时间限制】
1s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为freq.c。

不是很懂C2的选题标准,有些题卡人的要死,有些题(像这道),放在C1里面都是一道基础题,给大一新生做基本没什么问题。只需要判断一下特殊情况即可。

不过不管怎么样的题反正输入是绝对不正常的= =

“数独”游戏

【问题描述】
在9*9的棋盘上,在每个空格中填上1~9中的数字,每行、每列及9个3*3的九宫格中恰好包括1~9这九个数字。下面左图表示待定的棋盘,右图表示已经填写好的棋盘。
【输入形式】
输入文件为shudu.in。输入文件共9行,每行含9个数字,无分隔符。0表示待确定的空格。
【输出形式】
输出文件为shudu.out。输出共9行,每行9个数字,无分隔符。
【输入样例】
100006004 
008090050 
400300000 
800002040 
009605200 
060700005 
000007002 
080030400 
300200009
【输出样例】
193576824 
628491753 
457328961 
835912647 
719645238 
264783195 
946857312 
582139476 
371264589
【时间限制】
2s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为shudu.c。

之前是在这题上面WA了一个点,,也没办法debug。后来发现果然还是输入文件有问题,一行的末尾的确是有空格的,题面也不说清楚= = C2的输入处理果然就是坑

 把数独存入二维数组就好处理了,虽然之前没写过这题,不过真正写起来的时候倒还顺手,因为思路还是挺清晰的,就是DFS爆搜加回溯。从第一个点开始如果需要你填,那么就遍历哪些数字能填,然后选一个,开始填下一个位置的数字。填完一个数字之后需要告知该行该列以及他所处的九宫格的所有位置,这个数字已经填过了,不能再填这个数字了。(开始时有数字的格也需要登记一下)。这里我用的一个三维数组来存的,前两位存放该格的横纵坐标,第三维相当于该格的used数组,used[i]>0,说明该格不能填数字i了。

如果到了一个位置,发现这格没有数字能填了,就回溯到上一个格子,试试填下一个数字,就这样暴力DFS加回溯。需要注意的是,在填一个数字后,将该行该列和九宫格的所有位置登记这个数字已经使用,不能填写。那么回溯后则需要注销该登记过程,这个数字在这些位置又能使用了。

矩阵乘法C

【问题描述】
大矩阵乘法。
【输入形式】
文件arr.in中读入一个m行k列的整数矩阵a和一个k行n列的整数矩阵b(0 < m, k, n < 200000, m * k < 2000000, k * n < 3000000, m * n < 5000000)。
文件arr.in中有m + k行,前m行是矩阵a的元素aij,后k行是矩阵b的元素bij(-3000 < aij, bij < 3000)。
每行中相邻的两个元素之间以一个或多个空白符分隔。
【输出形式】
在标准输出上输出这两个矩阵的乘积。
输出结果为m行n列的矩阵,按整数右对齐方式输出,各列等宽,并保证矩阵中最长元素与其左侧的元素之间只有1个空格。
当最长元素位于第一列时,在该元素前留1个空格。(注意:在输出时,要严格计算相邻元素之间的空格个数)。
【输入样例】
12 89 
2 8 
1 2 3 
2 2 4
【输出样例】
190 202 392 
18 20 38
【时间限制】
200s
【空间限制】
65536KB
【上传文件】
上传c语言源程序,文件名为arr.c。

一眼看下去200s的时间限制也是跪了。但是本质上还是水题。

由于保证了m*n<5000000,主要考虑下应该怎么存矩阵,二维数组肯定是不行的。这里我用的是一个链表,链表上连接一个数组。数组元素表示列,链表表示行。注意这个数组要动态开辟内存,否则静态的话肯定会爆的。

所以先读一遍文件把mkn都算出来,然后再保存元素,最后再计算即可。

这题一开始WA了,找了半天发现我根本就没考虑负数的情况(包括前两次也一样),测试时压根连“-”出现的情况都没考虑。也就是说负号我都直接忽略了,当成整数来运算。

然而前两次居然全都过了!!!真是神奇。

然后这次需要严格保证输出格式,所以一定要用printf("%*d")的格式来写,也需要计算整个矩阵中最长的元素。这里注意下负号本身需要占一位所以负数计算的时候要多一位。

然后就没啥好说的了,之所以说是本质水题因为连用int存数组都能过= =

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值