NOIP2018 Day1
零年OI一场空,三道原题见祖宗。
t1道路铺设/积木大赛
题目描述
思路
NOIP的时候用的快乐暴力递归,理论上70分,洛谷上80分。
(其实考试的时候真的要想出来了正解,但是没有怎么实践,太气了!!
考试70分代码
/*暴力模拟 70分。 */
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn=100005;
const int inf=10005;
int d[maxn];
long long cnt=0;
int n;
void build(int l,int r){//暴力
if(l>r) return;
int s=1,v=inf;
for(int i=l;i<=r;i++) v=min(v,d[i]);
cnt+=v;
// printf("[%d,%d]:%d\n",l,r,v);
for(int i=l;i<=r;i++){
d[i]-=v;
if(d[i]==0){
build(s,i-1);
s=i+1;
}
}
build(s,r);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&d[i]);
build(1,n);
printf("%lld",cnt);
return 0;
}
正解
考虑下一块的高度和当前积木的高度:
如果大于:显然需要多搭(现在高度-当前高度)下。
如果小于:在搭当前这一块积木的时候就能顺便搭这一块,所以不做处理。
代码
#include <cstdio>
#include <iostream>
using namespace std;
int main(){
int n;scanf("%d",&n);
int ans;scanf("%d",&ans);//至少需要搭第一个的高度。
int now=ans;//记录当前积木的高度
for(int i=2;i<=n;i++){
int h;scanf("%d",&h);
if(h>now) ans+=(h-now);//如果后面的大于当前的高度 显然要多搭几下
//如果小于,那么在搭这一块的时候就能顺便把下一块给搭了
now=h;
}
printf("%d",ans);
return 0;
}
t2货币系统
题目描述
思路
考试的时候用的超级大筛子,得了90分。
考试80分代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxa=1005,maxn=105;
bool choose[maxa];//能被表示出来
int a[maxn];
int main(){
int t;scanf("%d",&t);
while(t--){
int cnt=0;
memset(choose,0,sizeof(choose));
choose[0]=1;
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
int end=a[n];
for(int i=1;i<=n;i++){
int v=a[i];
if(!choose[v]){
choose[v]=1;
cnt++;
for(int j=1;j*v<=end;j++){//枚举当前张数
int now=j*v;
for(int k=1;k<=end;k++){
if(now+k>end) break;
if(choose[k]) choose[k+now]=1;
}
}
}
}
printf("%d\n",cnt);
}
return 0;
}
正解
考试的思路与正解真的非常像了,只是有两个问题:
1、数组太小了,应该为25000(考试的时候看错ai的数据范围不然就有95了,尴尬。)
2、不用枚举张数,直接一张的时候就行了。
去掉枚举张数的循环就行了。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxa=25005,maxn=105;
bool choose[maxa];//能被表示出来
int a[maxn];
int main(){
int t;scanf("%d",&t);
while(t--){
int cnt=0;
memset(choose,0,sizeof(choose));
choose[0]=1;
int n;scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
int end=a[n];
for(int i=1;i<=n;i++){//当前的钱是否能够表示出来
if(!choose[a[i]]){
cnt++;
for(int j=0;j+a[i]<=end;j++) if(choose[j]) choose[j+a[i]]=1;
}
}
printf("%d\n",cnt);
}
return 0;
}