NOIP2016普及组试题题解

1.买铅笔

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,ans=1e9,a,b;
int main(){
	cin>>n;
	for(int i=1;i<=3;i++){
		cin>>a>>b;
		ans=min(ans,int(ceil(n*1.0/a)*b));
	}
	cout<<ans;
	return 0;
}

  

解题思路:

直接枚举每种包装的花费,取最小值即可

 

2.回文日期

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int days[13]={0,31,29,31,30,31,30,31,31,30,31,30,31};
int x1,x2,y3,m1,d1,y2,m2,d2,ans=0;
int turnday(int m,int d){
	return m*100+d+m/10*10000+m%10*100000+d/10*1000000+d%10*10000000;
}
int main(){
	cin>>x1>>x2;
	for(int i=1;i<=12;i++){
		for(int j=1;j<=days[i];j++){
			int t=turnday(i,j);
			if(t>=x1&&t<=x2)ans++;
		}
	}
	cout<<ans;
	return 0;
}

  

解题思路:

这道题有两种方法,第一种枚举年,反向构造月和日,判断日期是否合法,如果合法且在范围内,答案加一,代码相对繁琐;第二种枚举月和日,反向构造年,这样可以不用判断日期是否合法,只需判断日期是否在范围内即可,代码相对简炼

 

3.海港

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 3e5+39+7;
struct node{
	int id,tim;
	node(int id1,int tim1):id(id1),tim(tim1){}
};
int cnt=0,vh[N],n,k,t;
queue<node>q;
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>t>>k;
		for(int j=1,d;j<=k;j++){
			cin>>d;
			q.push(node(d,t));
			vh[d]++;
			if(vh[d]==1)cnt++;
		}
		while(q.size()&&t-q.front().tim>=86400){
			vh[q.front().id]--;
			if(!vh[q.front().id])cnt--;
			q.pop();		
		}
		cout<<cnt<<'\n';
	}
	return 0;
}

  

解题思路:

定义一个结构体,用来标记每名游客的国籍与时间,再用一个队列来存储,用一个桶来统计国籍,轮流统计答案即可

 

4.魔法阵

代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 2e4+39+7;
int vh[N],n,m,a[N*2],sumfre[N],sumend[N],ans[N][5];
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i];
		vh[a[i]]++;
	}
	for(int i=1;i<=n/9;i++){
		memset(sumfre,0,sizeof(sumfre));
		memset(sumend,0,sizeof(sumend));
		for(int j=i*2+1;j<=n;j++)sumfre[j]=sumfre[j-1]+vh[j]*vh[j-i*2];
		for(int j=n-i;j>0;j--)sumend[j]=sumend[j+1]+vh[j]*vh[j+i];
		for(int j=8*i+2;j<=n-i;j++){
			int t=sumfre[j-6*i-1]*vh[j]*vh[j+i];
			if(!t)continue;
			ans[j][3]+=t/vh[j];
			ans[j+i][4]+=t/vh[j+i];
		}
		for(int j=n-7*i-1;j>=2*i+1;j--){
			int t=sumend[j+6*i+1]*vh[j]*vh[j-2*i];
			if(!t)continue;
			ans[j-2*i][1]+=t/vh[j-i*2];
			ans[j][2]+=t/vh[j];
		}
	}
	for(int i=1;i<=m;i++){
		for(int j=1;j<=4;j++){
			cout<<ans[a[i]][j]<<' ';
		}
		cout<<'\n';
	}
	return 0;
}

  

解题思路:

使用前缀和计算sumfre和sunend,通过推导式子可以直接递推出每次增加多少,最终用ans数组统计即可

注意事项:

1.在求t时,因为题目是求每个物品的出现次数,需要用个数的前缀和乘第一个物品的个数乘第二个物品的个数,分别除以当前物品的个数去求得答案,所以是使用乘法,而不是加法,

posted @ 2023-05-22 22:20  天雷小兔  阅读(34)  评论(0)    收藏  举报