ccf csp2013.12

我终于想起这个被我咕了将近半个月的 任务了。。。从头开始做吧

T1 (简单的循环模拟

问题描述
  给定n个正整数,找出它们中出现次数最多的数。如果这样的数有多个,请输出其中最小的一个。
输入格式
  输入的第一行只有一个正整数n(1 ≤ n ≤ 1000),表示数字的个数。
  输入的第二行有n个整数s1, s2, …, sn (1 ≤ si ≤ 10000, 1 ≤ i ≤ n)。相邻的数用空格分隔。
输出格式
  输出这n个次数中出现次数最多的数。如果这样的数有多个,输出其中最小的一个。
样例输入
6
10 1 10 20 30 20
样例输出
10

要注意的是当从大到小查结果时,将a[i] > ma 改为a[i] >= ma,还有别忘了更新ma

满分代码:

#include <cstdio>
using namespace std;
int main(){
	int n, a[10002], tmp, ma = 0, ans;
	scanf("%d", &n);
	for(int i = 1; i <= 10000; i++) a[i] = 0;
	for(int i = 1; i <= n; i++)	{scanf("%d", &tmp);a[tmp]++;}
	for(int i = 1; i <= 10000; i++)
		if(a[i] > ma)	ans = i, ma = a[i];
	printf("%d\n", ans);
	return 0;
}

T2 (另一个简单的模拟

问题描述
  每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字、1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符(键盘上的减号),最后一位是识别码,例如0-670-82162-4就是一个标准的ISBN码。ISBN码的首位数字表示书籍的出版语言,例如0代表英语;第一个分隔符“-”之后的三位数字代表出版社,例如670代表维京出版社;第二个分隔之后的五位数字代表该书在出版社的编号;最后一位为识别码。
  识别码的计算方法如下:
  首位数字乘以1加上次位数字乘以2……以此类推,用所得的结果mod 11,所得的余数即为识别码,如果余数为10,则识别码为大写字母X。例如ISBN号码0-670-82162-4中的识别码4是这样得到的:对067082162这9个数字,从左至右,分别乘以1,2,…,9,再求和,即0×1+6×2+……+2×9=158,然后取158 mod 11的结果4作为识别码。
  编写程序判断输入的ISBN号码中识别码是否正确,如果正确,则仅输出“Right”;如果错误,则输出是正确的ISBN号码。
输入格式
  输入只有一行,是一个字符序列,表示一本书的ISBN号码(保证输入符合ISBN号码的格式要求)。
输出格式
  输出一行,假如输入的ISBN号码的识别码正确,那么输出“Right”,否则,按照规定的格式,输出正确的ISBN号码(包括分隔符“-”)。
样例输入
0-670-82162-4
样例输出
Right
样例输入
0-670-82162-0
样例输出
0-670-82162-4

注意最后一位是0~9或者X,所以对于%11后为10的情况要特殊处理

满分代码:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;

int main(){
	string str;
	cin >> str;
	char end;
	int standard = 0, count = 1, len = str.length();
	//0-670-82162-4
	for(int i = 0; i < len - 1; i++)
		if(str[i] >= '0' && str[i] <= '9')
			standard += (str[i] - '0') * (count++);
	standard %= 11;
	if(standard == 10)
		end = 'X';
	else
		end = standard + '0';
	if(end == str[len - 1])
		printf("Right");
	else{
		str[len - 1] = end;
		cout << str;
	}	
	return 0;
}

注意下面两个都是错误的:

int main(){
	string str;
	cin >> str;
//	char end;
	int standard = 0, count = 1, len = str.length();
	//0-670-82162-4
	for(int i = 0; i < len - 1; i++)
		if(str[i] >= '0' && str[i] <= '9')
			standard += (str[i] - '0') * (count++);
	standard %= 11;
//	if(standard == 10)
//		end = 'X';
//	else
//		end = standard + '0';
	if(standard == (str[len - 1] - '0'))
		printf("Right");
	else{
		str[len - 1] = standard + '0';
		cout << str;
	}	
	return 0;
}
/*
这个是因为完全忘掉了有X这回事
*/
int main(){
	string str;
	cin >> str;
//	char end;
	int standard = 0, count = 1, len = str.length();
	//0-670-82162-4
	for(int i = 0; i < len - 1; i++)
		if(str[i] >= '0' && str[i] <= '9')
			standard += (str[i] - '0') * (count++);
	standard %= 11;
//	if(standard == 10)
//		end = 'X';
//	else
//		end = standard + '0';
	if(standard == (str[len - 1] - '0'))
		printf("Right");
	else{
		if(standard == 10)
			str[len - 1] = 'X';
		else 
			str[len - 1] = standard + '0';
		cout << str;
	}	
	return 0;
}
/*
这个是因为更改和X有关情况时值更改了else部分,上面的if判断会出错
*/

T3 (单调不上升子序列

问题描述
  在横轴上放了n个相邻的矩形,每个矩形的宽度是1,而第i(1 ≤ i ≤ n)个矩形的高度是hi。这n个矩形构成了一个直方图。例如,下图中六个矩形的高度就分别是3, 1, 6, 5, 2, 3。
  请找出能放在给定直方图里面积最大的矩形,它的边要与坐标轴平行。对于上面给出的例子,最大矩形如下图所示的阴影部分,面积是10。
输入格式
  第一行包含一个整数n,即矩形的数量(1 ≤ n ≤ 1000)。
  第二行包含n 个整数h1, h2, … , hn,相邻的数之间由空格分隔。(1 ≤ hi ≤ 10000)。hi是第i个矩形的高度。
输出格式
  输出一行,包含一个整数,即给定直方图内的最大矩形的面积。
样例输入
6
3 1 6 5 2 3
样例输出
10

显然,对于这个问题,每个矩形必然受最矮的柱形限制,所以我们可以对于每个柱形,向左右同时寻找单调不下降的柱形(指两端),保证这个柱形就是那个限制点

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;

int main(){
	int n, cnt, ans = 0;
	int h[10002];
	scanf("%d", &n);
	for(int i = 1; i <= n; i++)
		scanf("%d", &h[i]);
	for(int i = 1; i <= n; i++){
		cnt = 0;
		for(int j = i - 1; j >= 1; j--){
			if(h[j] < h[i])
				break;
			cnt ++;
		}
		for(int j = i; j<= n; j++){
			if(h[j] < h[i])
				break;
			cnt ++;
		}
		ans = max(ans, cnt * h[i]);
	}
	printf("%d\n", ans);
	return 0;
}
/*
感动
这是好久以来重新打代码之后的第一次一遍过
*/

T4(又名:一个人可以有多么善变

问题描述
  我们把一个数称为有趣的,当且仅当:
  1. 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次。
  2. 所有的0都出现在所有的1之前,而所有的2都出现在所有的3之前。
  3. 最高位数字不为0。
  因此,符合我们定义的最小的有趣的数是2013。除此以外,4位的有趣的数还有两个:2031和2301。
  请计算恰好有n位的有趣的数的个数。由于答案可能非常大,只需要输出答案除以1000000007的余数。
输入格式
  输入只有一行,包括恰好一个正整数n (4 ≤ n ≤ 1000)。
输出格式
  输出只有一行,包括恰好n 位的整数中有趣的数的个数除以1000000007的余数。
样例输入
4
样例输出
3

还没写,大致思路:
  1. 对于已经出现了 3 3 3的情况,对后面直接取 A 剩 余 位 数 3 A_{剩余位数}^{3} A3
  2. 对于还没有出现 3 3 3的情况,后面分为取 3 3 3和不取 3 3 3两种情况
  3. 对于 1 1 1 0 0 0也是如此
我在干啥呢????
  1. 大概是直接进行递归,终点是当前位为4,每一次返回 种 类 数 % 1000000007 种类数\%1000000007 %1000000007
  2. 中间要注意“出现1之后不能再次出现0”和“出现3之后不能再次出现2”的限制
我又改主意了。。。
  1. 这个题终点为位数达到n比较好吧
  2. 每一位加一次种类数,,似乎简单又可行
  3. 怎么回事我的数字这么大,哦原来是忘记了 它的数字只包含0, 1, 2, 3,且这四个数字都出现过至少一次 里面的 且这四个数字都出现过至少一次的要求
  4. 呀不简单,怎样才能保证每一个数都出现过呢
  5. 实现不了啊下一个
我,,绝望

我十分认真地怀疑,我又要用我蹩脚的dp来做这道题了,可是上一次的第三步还是做不到啊啊啊啊啊,搜答案去了
呜呜呜为什么用dp这么简单

把状态分类然后最终答案取使用过全部数字的状态类就可以了呀!!!!
  1. 显然第一位只能取2(0不让首位,1的话0就出现不了,3的话2就出现不了)由此类推,第二位只能取0,2,3,一直到出现了0之后才能取1,哦对了我们只需要知道第一位取啥就可以了,有了开头就行,后面的由上方加粗字体解决
  2. 状态分类可分为以下几种:(根据依赖关系可以得知有下面几种)
第0种  使用过2,剩余0 1 3

第1种 使用过0 2,剩余1 3

第2种 使用过0 1 2,剩余3

第3种 使用过0 2 3,剩余1

第4种 使用过2 3,剩余0 1

第5种 全部使用过
  1. 根据状态之间的转化进行递推
  2. 需要注意的是,不光int会爆,long也会,,只能用long long
#include <iostream>
#include<stdio.h>
#include<cstring>
using namespace std;
const int mod = 1000000007; 
long long a[1002][6];
/*        used      
a[][0]    2
a[][1]    2, 3       comfrom(2) or(2, 3)
a[][2]    0, 2       comfrom(2) or(0, 2)
a[][3]    0, 2, 3    comefrom( 0, 2) or ( 2, 3) or (0, 2 ,3)
a[][4]    0, 1, 2    comefrom(0,2) or (0, 1, 2) 
a[][5]    0, 1, 2, 3 comefrom(0, 2, 3) or (0, 1, 2) or (0, 1, 2, 3)
*/
int main()
{
    int n;
	scanf("%d", &n);
	memset(a, 0, sizeof(a));
//	a[1][0] = 1;// the start
	for(int i = 1; i <= n; i++){
		a[i][0] = 1;
		a[i][1] = (a[i - 1][0] + a[i - 1][1]) % mod;
		a[i][2] = (a[i - 1][0] + a[i - 1][2] * 2) % mod;
		a[i][3] = (a[i - 1][2] + a[i - 1][1] + a[i - 1][3] * 2) % mod;
		a[i][4] = (a[i - 1][2] + a[i - 1][4] * 2) % mod;
		a[i][5] = (a[i - 1][3] + a[i - 1][4]  + a[i - 1][5] * 2) % mod;
	}
	cout << a[n][5] % mod;
    return 0;
}

此处纪念一下错误代码3号:

/*
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <iostream>
using namespace std;
int n;
long ans = 0;
const int mod = 1000000007;
void dfs(int add, bool haveone, bool havethree, int tot){
	if(tot == n) return;
	ans = (ans + add % mod) % mod;
	cout <<"tot = " << tot << "   add:" << add << endl;
	if(!haveone && !havethree){// no limit
		dfs(2, false, false, tot + 1);//0 2
		dfs(1, false, true, tot + 1);//3
		dfs(1, true, false, tot + 1);//1
	}
	else if(haveone && !havethree){//no 0 but can 2
		dfs(2, true, false, tot + 1);//1 2
		dfs(1, true, true, tot + 1);//3
	}
	else if(!haveone && havethree){//no 2 but can 0
		dfs(2, false, true, tot + 1);//0 3
		dfs(1, true, true, tot + 1);//1
	}
}

int main(){
	scanf("%d", &n);
//	if(n == 4) {
//		printf("3\n");
//		return 0;	
//	}
	dfs(1, false, false, 0);//2 
	cout << endl << endl;
	dfs(1, false, true, 0);// 3
	cout << endl << endl;
	dfs(1, true, false, 0);// 1
	cout << endl << endl;
	cout << ans << endl;
	return 0;
}
*/
T5 就是简单的搜索问题

不行写了一点太困了明天写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值