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时,因为题目是求每个物品的出现次数,需要用个数的前缀和乘第一个物品的个数乘第二个物品的个数,分别除以当前物品的个数去求得答案,所以是使用乘法,而不是加法,

浙公网安备 33010602011771号