Saito Asuka saiko!!!

有些走累了呢 有些走累了呢 虽然以那麼平凡的表现 来形容人生的漫长道路 想稍稍休息下呢 想稍稍休息下呢 时间每分每刻都这样残酷 将我紧拖著前行...

NOIP2018 Day1

零年OI一场空,三道原题见祖宗。

t1道路铺设/积木大赛

题目描述

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货币系统

题目描述

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;
}
posted @ 2018-11-10 17:48  斋藤飞鸟  阅读(127)  评论(0编辑  收藏  举报
动画加载完毕