2020.2.3普及C组模拟赛2

普及C组模拟赛2

1.【10.5NOIP普及模拟】sort

  小x和小y是好朋友。小y的成绩很差,以至于 GPA(平均绩点)在系内倒数。系内一共有 N 位同学,每位同学有自己的 GPA,以及已修学分数,定义 GPT = GPA ×已修学分数。小x为了帮助小y提高成绩,给小y提了一个要求:新学期的 GPA 要超过系内排名第 K 位的同学。 为了帮助理解,给出一个例子:

  现在给出系里面每位同学的 GPT(只有一位小数),以及他们的已修学分。你需要帮助小y把排名 第 K 位的同学的 GPA 求出来。

输入

第 1 行2 个整数 N, K。

第 2- (N + 1) 行,每行 1 个非负实数和 1 个整数,分别表示 GPT 和已 修学分数。

注意:所有同学的学分都在 [1, 250] 的范围。

输出

第 1 行1 个实数,表示排名第 K 同学的 GPA,保留 2 位小数输出。

样例输入

5 3

73 20

79.8 21

72.6 22

85.1 23

65.7 18

样例输出

3.65

数据范围限制

对于 50% 的数据:1 ≤ N ≤ 100。

对于 100% 的数据:1 ≤ K ≤ N ≤ 100000,GPT 小数点后至多 1 位,GPA 至多 4.0。
分析
快排一波

AC代码

#include<iostream>
#include<iomanip>
#include<algorithm>
#include<cstdio>
using namespace std;
int n,k,b;
struct stu//结构体
{
	double GPT,GPA;
}a[100005];
bool cmp(stu x,stu y)//快排
{
	if(x.GPA==y.GPA)return x.GPT>y.GPT;
	return x.GPA>y.GPA;
}
int main()
{
	freopen("sort.in","r",stdin);
	freopen("sort.out","w",stdout);
	cin>>n>>k;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i].GPT>>b;
		a[i].GPA=a[i].GPT/b;//公式转化一下
	}
	sort(a+1,a+n+1,cmp);//快排
	cout<<fixed<<setprecision(2)<<a[k].GPA;
	fclose(stdin);
	fclose(stdout);
}

2.【10.5NOIP普及模拟】sum
题目描述

小x有很多糖果,分成了 N 堆,排成一列。小x说,如果小y能迅速求出第 L 堆到第 R 堆一 共有多少糖果,就把这些糖果都给他。

现在给出每堆糖果的数量,以及每次询问的 L 和 R,你需要帮助小y,把每次询问的结果求出来。 注意,你不需要考虑糖果被小y取走的情况。

输入

第 1 行2 个整数 N, M, 分别表示堆数和询问数量。

第 2 行N 个整数 Ai,表示第 i 堆糖果的数 量。

第 3- (M + 2) 行,每行 2 个整数 Li, Ri,表示第 i 个询问是 [Li, Ri]。

输出

M 行,对于每个询问,输出对应的和。

样例输入

5 5

1 2 3 4 5

1 5

2 4

3 3

1 3

3 5

样例输出

15

9

3

6

12

数据范围限制

对于 50% 的数据:1 ≤ N, M ≤ 100。

对于 100% 的数据:1 ≤ N,M ≤ 100000,0 ≤ Ai ≤ 10000,1 ≤ Li ≤ Ri ≤ N。
正解
前缀和

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
long long n,m,b,l,r,a[100005];
int main()
{
	freopen("sum.in","r",stdin);
	freopen("sum.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&b);
		a[i]=a[i-1]+b;//前缀和
	}
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&l,&r);
		printf("%d\n",a[r]-a[l-1]);//记住是l-1,不是l
	}
	fclose(stdin);
	fclose(stdout);
}

3.【10.5NOIP普及模拟】count
题目描述

 小x开发了一个奇怪的游戏,这个游戏的是这样的:一个长方形,被分成 N 行 M 列的格子,第 i 行第 j 列的格子记为 (i, j),就是说,左上角的格子是 (1, 1),右下角的格子是 (N, M)。开始的时候,小y在 (1, 1),他需要走到 (N, M)。每一步,小y可以走到正右方或者正下方的一个格子。具体地说,如小y现在在 (x, y),那么他可以走到 (x, y + 1) 或 (x + 1, y)。当然,小y不能走出离开这个长方形。

 每个格子有积分,用一个 1~10 的整数表示。经过这个格子,就会获取这个格子的积分(起点和终 点的积分也计算)。通过的方法是:到达 (N, M) 的时候,积分恰好为 P 。

 现在给出这个长方形每个格子的积分,你需要帮助小y,求出从起点走到终点,积分为 P 的线路有多少条。

输入

第 1 行3 个整数 N, M, P 。

接下来 N 行,每行 M 个整数 Aij ,表示格子 (i, j) 的积分。

输出

1 行1 个整数,表示积分为 P 线路的数量。

因为数值太大,你只需要输出结果除以 (10^9 + 7) 的 余数。

样例输入

3 3 9

2 2 1

2 2 2

1 2 2

样例输出

2

数据范围限制

对于 50% 的数据:1 ≤ N, M ≤ 10。

对于 100% 的数据:1 ≤ N, M ≤ 100,0 ≤ Aij ≤ 10。
正解
DP

AC代码

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,p,a[105][105];
long long f[105][105][1505];
int main()
{
	freopen("count.in","r",stdin);
	freopen("count.out","w",stdout);
	cin>>n>>m>>p;
	for(int i=1;i<=n;i++)
	 for(int j=1;j<=m;j++)
	  cin>>a[i][j];//输入
	f[1][1][a[1][1]]=1;//初值
	for(int i=1;i<=n;i++)//dp
	 for(int j=1;j<=m;j++)
	  for(int k=1;k<=p;k++)
	   if(k-a[i][j]>0)
	    f[i][j][k]=(f[i-1][j][k-a[i][j]]+f[i][j-1][k-a[i][j]])%1000000007;//公式
	cout<<f[n][m][p];  
	fclose(stdin);
	fclose(stdout);
}

4.【10.5NOIP普及模拟】ranking
题目描述

 小x有n个小姊妹(根据典故,我们假设n≤3000)。他每天都喜欢按不同标准给小姊妹们排(da)序(fen)。今天,他突然对小姊妹们的名字产生了兴趣。他觉得小姊妹的魅力和她们的名字有密切联系,于是他觉得所有有相似的名字的小姊妹必须排在一起。
 相似是指,名字的开头一个或若干个连续字母相同。

 于是,小x定下了如下规则:

 在任何以同样的字母序列开头的名字之间,所有名字开头必须是同样的字母序列。

 比如,像MARTHA和MARY这两个名字,它们都以MAR开头,所以像MARCO或MARVIN这样的名字可以插入这两个名字中间,而像MAY这样的就不行。

 显然,按字典序排序是一个合法的排序方案,但它不是唯一的方案。你的任务就是计算出所有合法的方案数。考虑到答案可能很大,输出答案 mod 1 000 000 007。

输入

第一行一个整数n,小x的小姊妹个数。

第2~n+1行,每行一个字符串,代表这个小姊妹的名字。

输出

一行一个整数,合法的方案数。

样例输入

3

IVO

JASNA

JOSIPA

样例输出

4

数据范围限制

对于60%的数据:3 ≤ n ≤ 10。

对于100%的数据:

3 ≤ n ≤ 3000

1 ≤ 字符串长度 ≤ 3000,并且只含有大写字母。

正解
字符串+搜索

AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm> 
using namespace std;
const int M=1000000007;
long long n,maxn,s[4000]={0,1};
struct stu
{
	char aa[4000];
}a[4000];
bool cmp(stu x,stu y)//快排
{
	return(strcmp(x.aa,y.aa)<0);
}
long long dfs(int x,int y,int z)//搜索
{
	long long ans=1,o=x,t=1;
	if(z>maxn)return s[y-x+1];
	for(int i=x+1;i<=y;i++)
	 if(a[i].aa[z]!=a[o].aa[z])
	 {
		t++;
		ans=ans*dfs(o,i-1,z+1)%M;
		o=i;
	 }
	if(o!=y)ans=ans*dfs(o,y,z+1)%M;
	ans=ans*s[t]%M;
}
int main(){
    freopen("ranking.in","r",stdin);
	freopen("ranking.out","w",stdout);
    cin>>n;
	for(int i=1;i<=n;i++)
	{
	    cin>>a[i].aa;//string
	    if(strlen(a[i].aa)-1>maxn)maxn=strlen(a[i].aa)-1;
	} 
	for(int i=1;i<=n;i++)
	 for(int j=strlen(a[i].aa);j<=maxn;j++)
	 	a[i].aa[j]='*';
	for(int i=2;i<=3000;i++)
		s[i]=s[i-1]*i%M;
    sort(a+1,a+n+1,cmp);//快排
    cout<<dfs(1,n,0); 
}

赛后分析

1.
直接AC了
2.
前缀和出了问题,最后AC
3.
50分暴力,后来通过视频AC
4.
cxy(陈博)巨佬告诉我思路,然后AC

谢谢观看

2020.2.3普及C组模拟赛22020.2.3普及C组模拟赛2 SSL_李恪佳 发布了48 篇原创文章 · 获赞 77 · 访问量 1601 私信 关注
上一篇:大牛给计算机专业学生的7个建议


下一篇:写于2020年新年之际