记录洛谷刷题qaq
[NOIP2002 普及组] 选数
题目描述
已知 n n n 个整数 x 1 , x 2 , ⋯ , x n x_1,x_2,\cdots,x_n x1,x2,⋯,xn,以及 1 1 1 个整数 k k k( k < n k<n k<n)。从 n n n 个整数中任选 k k k 个整数相加,可分别得到一系列的和。例如当 n = 4 n=4 n=4, k = 3 k=3 k=3, 4 4 4 个整数分别为 3 , 7 , 12 , 19 3,7,12,19 3,7,12,19 时,可得全部的组合与它们的和为:
3 + 7 + 12 = 22 3+7+12=22 3+7+12=22
3 + 7 + 19 = 29 3+7+19=29 3+7+19=29
7 + 12 + 19 = 38 7+12+19=38 7+12+19=38
3 + 12 + 19 = 34 3+12+19=34 3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数: 3 + 7 + 19 = 29 3+7+19=29 3+7+19=29。
输入格式
第一行两个空格隔开的整数 n , k n,k n,k( 1 ≤ n ≤ 20 1 \le n \le 20 1≤n≤20, k < n k<n k<n)。
第二行 n n n 个整数,分别为 x 1 , x 2 , ⋯ , x n x_1,x_2,\cdots,x_n x1,x2,⋯,xn( 1 ≤ x i ≤ 5 × 1 0 6 1 \le x_i \le 5\times 10^6 1≤xi≤5×106)。
输出格式
输出一个整数,表示种类数。
样例 #1
样例输入 #1
4 3
3 7 12 19
样例输出 #1
1
提示
【题目来源】
NOIP 2002 普及组第二题
代码如下:
#include <stdio.h>
#include <stdlib.h>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//判断素数
int sum, m, n, k, num[21], i;//sum是m个数的总数和 ,m表示素数的个数
int SU(int x){
if(x==0||x==1)
return 0;
for(i = 2;i < x;i++){
if(x%i==0){
return 0;
break;
}
}
if(i>=x)
return 1;
}
//抽数
void CHOU(int N,int now){//num表示还差num个数到k;now表示现在抽到了第now个数字
if(N==0){
m += SU(sum);
}
else{
now++;
for(int i = now;i <= n;i++){
sum += num[i];
N--;
CHOU(N,i);
sum -= num[i];//这两句是为了清空之前选的那个数(的痕迹)
N++;
}
}
}
int main(int argc, char *argv[]) {
while(scanf("%d%d",&n,&k)!=EOF){
for(int i = 1;i <= n;i++){
scanf("%d",&num[i]);
}
CHOU(k,0);
printf("%d\n",m);
}
return 0;
}
[NOIP2003 普及组] 乒乓球
题目背景
国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中 11 11 11 分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白 11 11 11 分制和 21 21 21 分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。
题目描述
华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 11 11 11 分制和 21 21 21 分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中 W \texttt W W 表示华华获得一分, L \texttt L L 表示华华对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW \texttt{WWWWWWWWWWWWWWWWWWWWWWLW} WWWWWWWWWWWWWWWWWWWWWWLW
在 11 11 11 分制下,此时比赛的结果是华华第一局 11 11 11 比 0 0 0 获胜,第二局 11 11 11 比 0 0 0 获胜,正在进行第三局,当前比分 1 1 1 比 1 1 1。而在 21 21 21 分制下,此时比赛结果是华华第一局 21 21 21 比 0 0 0 获胜,正在进行第二局,比分 2 2 2 比 1 1 1。如果一局比赛刚开始,则此时比分为 0 0 0 比 0 0 0。直到分差大于或者等于 2 2 2,才一局结束。
你的程序就是要对于一系列比赛信息的输入( WL \texttt{WL} WL 形式),输出正确的结果。
输入格式
每个输入文件包含若干行字符串,字符串有大写的 W \texttt W W 、 L \texttt L L 和 E \texttt E E 组成。其中 E \texttt E E 表示比赛信息结束,程序应该忽略 E \texttt E E 之后的所有内容。
输出格式
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是 11 11 11 分制下的结果,第二部分是 21 21 21 分制下的结果,两部分之间由一个空行分隔。
样例 #1
样例输入 #1
WWWWWWWWWWWWWWWWWWWW
WWLWE
样例输出 #1
11:0
11:0
1:1
21:0
2:1
提示
每行至多 25 25 25 个字母,最多有 2500 2500 2500 行。
(注:事实上有一个测试点有 2501 2501 2501 行数据。)
【题目来源】
NOIP 2003 普及组第一题
代码如下:
#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
char str[100010];
int cnt=0;
void show(int n){
int a=0,b=0;
for(int i=0;i<cnt;i++){
if(str[i]=='W') a++;
if(str[i]=='L') b++;
if((a>=n||b>=n)&&abs(a-b)>=2){
printf("%d:%d\n",a,b);
a=b=0;
}
}
//新的一轮刚开始,或上一局没有打完
printf("%d:%d\n",a,b);
}
int main(){
char ch;
while(scanf("%c",&ch)&&ch!='E'){
if(ch=='W'||ch=='L'){
str[cnt++]=ch;
}
}
show(11);
printf("\n");
show(21);
}
[NOIP2003 普及组] 栈
题目背景
栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表。
栈有两种最重要的操作,即 pop(从栈顶弹出一个元素)和 push(将一个元素进栈)。
栈的重要性不言自明,任何一门数据结构的课程都会介绍栈。宁宁同学在复习栈的基本概念时,想到了一个书上没有讲过的问题,而他自己无法给出答案,所以需要你的帮忙。
题目描述
宁宁考虑的是这样一个问题:一个操作数序列, 1 , 2 , … , n 1,2,\ldots ,n 1,2,…,n(图示为 1 到 3 的情况),栈 A 的深度大于 n n n。
现在可以进行两种操作,
- 将一个数,从操作数序列的头端移到栈的头端(对应数据结构栈的 push 操作)
- 将一个数,从栈的头端移到输出序列的尾端(对应数据结构栈的 pop 操作)
使用这两种操作,由一个操作数序列就可以得到一系列的输出序列,下图所示为由 1 2 3
生成序列 2 3 1
的过程。
(原始状态如上图所示)
你的程序将对给定的 n n n,计算并输出由操作数序列 1 , 2 , … , n 1,2,\ldots,n 1,2,…,n 经过操作可能得到的输出序列的总数。
输入格式
输入文件只含一个整数 n n n( 1 ≤ n ≤ 18 1 \leq n \leq 18 1≤n≤18)。
输出格式
输出文件只有一行,即可能输出序列的总数目。
样例 #1
样例输入 #1
3
样例输出 #1
5
提示
【题目来源】
NOIP 2003 普及组第三题
代码如下:
#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
long n,f[20][20];
long dfs(int x,int y){
if(f[x][y]!=0) return f[x][y];//记忆化,走过的方案直接调用
if(x==0) return 1;//当操作队列里没有了,就只有一种方案了
if(y>0) f[x][y]+=dfs(x,y-1);//栈里不为空的时候才可以把栈里的元素推出
f[x][y]+=dfs(x-1,y+1);//操作队列里元素减一,栈里元素加一
return f[x][y];//返回方案值
}
int main()
{
scanf("%d",&n);
printf("%lld\n",dfs(n,0));
return 0;
}
[NOIP2005 普及组] 采药
题目描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”
如果你是辰辰,你能完成这个任务吗?
输入格式
第一行有 2 2 2 个整数 T T T( 1 ≤ T ≤ 1000 1 \le T \le 1000 1≤T≤1000)和 M M M( 1 ≤ M ≤ 100 1 \le M \le 100 1≤M≤100),用一个空格隔开, T T T 代表总共能够用来采药的时间, M M M 代表山洞里的草药的数目。
接下来的 M M M 行每行包括两个在 1 1 1 到 100 100 100 之间(包括 1 1 1 和 100 100 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出格式
输出在规定的时间内可以采到的草药的最大总价值。
样例 #1
样例输入 #1
70 3
71 100
69 1
1 2
样例输出 #1
3
提示
【数据范围】
- 对于 30 % 30\% 30% 的数据, M ≤ 10 M \le 10 M≤10;
- 对于全部的数据, M ≤ 100 M \le 100 M≤100。
【题目来源】
NOIP 2005 普及组第三题
代码如下:
#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
int max(int i,int j)
{
if(i > j)
return i;
else
return j;
}
int w[105], val[105];
int dp[1005];
int main()
{
int t,m,res=-1;
scanf("%d%d",&t,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&w[i],&val[i]);
}
for(int i=1;i<=m;i++)
{
for(int j=t;j>=0;j--)
{
if(j>=w[i])
{
dp[j]=max(dp[j-w[i]]+val[i], dp[j]);
}
}
}
printf("%d",dp[t]);
return 0;
}
[NOIP2001 普及组] 装箱问题
题目描述
有一个箱子容量为 V V V,同时有 n n n 个物品,每个物品有一个体积。
现在从 n n n 个物品中,任取若干个装入箱内(也可以不取),使箱子的剩余空间最小。输出这个最小值。
输入格式
第一行共一个整数 V V V,表示箱子容量。
第二行共一个整数 n n n,表示物品总数。
接下来 n n n 行,每行有一个正整数,表示第 i i i 个物品的体积。
输出格式
- 共一行一个整数,表示箱子最小剩余空间。
样例 #1
样例输入 #1
24
6
8
3
12
7
9
7
样例输出 #1
0
提示
对于 100 % 100\% 100% 数据,满足 0 < n ≤ 30 0<n \le 30 0<n≤30, 1 ≤ V ≤ 20000 1 \le V \le 20000 1≤V≤20000。
【题目来源】
NOIP 2001 普及组第四题
代码如下:
#include<string.h>
#include<stdio.h>
#include<math.h>
#include <stdlib.h>
int m,n; //m即箱子容量V
int f[20010];
int w[40];
int main(){
int i,j;
scanf("%d%d",&m,&n);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
for(int i=1;i<=n;i++)
{
for(int j= m; j>=w[i];j--)
{ // 注意:这里必须是从m到w[i],否则一个物体会被多次装入箱子,见例1
if(f[j]<f[j-w[i]]+w[i]){
f[j]=f[j-w[i]]+w[i];
}
}
}
printf("%d\n",m-f[m]);
}