NOIP 模拟总结10.17

T1
低价购买
问题描述:
“低价购买”这条建议是在奶牛股票市场取得成功的一半规则。要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买;再低价购买”。每次你购买一支股票,你必须用低于你上次购买它的价格购买它。买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数。你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票。每次购买都必须遵循“低价购买;再低价购买”的原则。写一个程序计算最大购买次数。
这里是某支股票的价格清单:
日期 1 2 3 4 5 6 7 8 9 10 11 12
价格 68 69 54 64 68 64 70 67 78 62 98 87
最优秀的投资者可以购买最多4次股票,可行方案中的一种是:
日期 2 5 6 10
价格 69 68 64 62

输入说明:
第1行: N (1 <= N <= 5000),股票发行天数
第2行: N个数,是每天的股票价格。(0<=价格<=100000)

输出说明:
输出文件仅一行包含两个数:最大购买次数和拥有最大购买次数的方案数(<=231)当二种方案“看起来一样”时(就是说它们构成的价格队列一样的时候),这2种方案被认为是相同的。

样例输入:
12
68 69 54 64 68 64 70 67 78 62 98 87

样例输出:
4 2

请注意题面描述最后一行
要注意判重
!!!
没判重的dxg 只得了40分

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
int w[10005];
int f[10005];
int g[10005];
int pre[10005];
int wei[10005];
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
inline int dng(int l,int r,int val){
    while(l<=r){
        int mid=(l+r)/2;
        if(f[mid]==val) return mid;
        else if(f[mid]>=val) r=mid-1;
        else l=mid+1;
    }
    return l;
}
int main(){
    freopen("buylow.in","r",stdin);
    freopen("buylow.out","w",stdout);
    n=read();
    for(register int i=1;i<=n;++i) {
        int v;
        v=read();
        w[n-i+1]=v;
        f[i]=1;
    }
    for(register int i=2;i<=n;i++){
        for(register int j=1;j<i;j++){
             if(w[j]<w[i]){
                f[i]=max(f[i],f[j]+1);
             }
        }
    }
    for(register int i=1;i<=n;i++) 
     if(f[i]==1) g[i]=1;
     for(register int i=2;i<=n;i++){
        for(register int j=1;j<=i-1;j++){
            if(w[i]==w[j]&&f[i]==f[j])
               g[j]=0;
            else if(w[i]>w[j]&&f[i]==f[j]+1){
                g[i]+=g[j];
            }
        }
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,f[i]);
    }
    printf("%d ",ans);
    int ans1=0;
    for(int i=1;i<=n;i++){
        if(f[i]==ans){
            ans1+=g[i];
        }
    }
    printf("%d",ans1);
    return 0;
}

T2
通讯线路
问题描述:
某地区共有n座村庄,每座村庄的坐标用一对整数(x, y)表示,现在要在村庄之间建立通讯网络。通讯工具有两种,分别是需要铺设的普通线路和卫星设备。卫星设备数量有限,只能给k个村庄配备卫星设备。拥有卫星设备的村庄互相间直接通讯;铺设了线路的村庄之间也可以通讯。卫星分配是不受限制的。
问怎样合理的分配卫星和铺设线路,使得在保证每两座村庄之间都可以直接或间接地通讯的前提下,铺设线路的总长度最短。

输入说明:
第一行两个数:n,k(0≤k≤n≤2000)
接下来n行,每行两个整数(x,y)数描述一个村庄。(-10000≤x,y≤10000)

输出说明:
仅一行,代表总长度,精确到0.0001

样例输入:
20 8
137 824
761 14
68 151
194 758
149 138
314 90
809 404
964 877
471 66
177 546
73 977
397 560
928 653
199 486
736 44
985 801
621 509
444 140
88 508
556 327

样例输出:
1355.4195

这是我在考场上除了spfa想出的第一个正解
(我不会告诉你第一次数组开大了QAQ)
以下是考试代码~直接过掉

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
int n,k;
double dis[2005][2005];
int fa[20005];
double bian[2005];
int find(int x){
    if(fa[x]!=x) fa[x]=find(fa[x]);
    return fa[x];
}
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct NODE{
    int x,y;
}zh[2005];
inline double cacu(int x,int y,int xx,int yy){
    double x1=fabs(double(x)-double(xx));
    double x2=fabs(double(y)-double(yy));
    return sqrt(x1*x1+x2*x2);
}
int tot=0;
struct tree{
    int l;
    int r;
    double v;
}tr[2001005];
inline void add(int x,int y,double z){
    ++tot;
    tr[tot].l=x;
    tr[tot].r=y;
    tr[tot].v=z;
}
inline bool cmp(tree a,tree b){
    return a.v<b.v;
}
int main(){
    freopen("line.in","r",stdin);
    freopen("line.out","w",stdout);
    n=read();
    k=read();
    for(register int i=1;i<=n;i++){
        zh[i].x=read();
        zh[i].y=read();
    }
    for(register int i=1;i<=n;i++) fa[i]=i;
    for(register int i=1;i<=n;i++){
        for(register int j=1;j<=n;j++){
            if(i!=j) 
            dis[i][j]=dis[j][i]=cacu(zh[i].x,zh[i].y,zh[j].x,zh[j].y);
            if(i==j) dis[i][j]=dis[j][i]=0.0;
        }
    }
    for(register int i=1;i<=n;i++){
        for(register int j=i+1;j<=n;j++){
            add(i,j,dis[i][j]);
        }
    }
    int anss=0;
    double minn=0.0;
    sort(tr+1,tr+tot+1,cmp);
    for(register int i=1;i<=tot;i++){
        int x=tr[i].l;
        int y=tr[i].r;
        int fx=find(x);
        int fy=find(y);
        if(fx!=fy){
            ++anss;
            fa[fx]=fy;
            bian[anss]=tr[i].v;
            minn+=bian[anss];
        }
        if(anss==n-1) break;
    }
    sort(bian+1,bian+anss+1);
    for(register int i=anss;i>=n-k+1;i--)
       minn-=bian[i];
       printf("%.4lf",minn);
    return 0;
}

T3
墙壁粉刷
问题描述:
现在需要粉刷一列墙壁,墙壁被分成n段,为了节约用钱,科学家决定只粉刷其中一些段,同时为了美观,科学家要求每连续的m段墙壁中至少有两块被粉刷,现在已知粉刷每一段墙壁的费用。科学家要你帮他求出最少的费用。

输入说明:
第一行,n和m(2<=n <=10000,2<=m<=100)
第二行,n个非负整数,第i个数为粉刷第i段的费用。(费用<=10000)

输出说明:
一行,最小费用。

样例输入:
8 3
6 7 10 1 7 8 5 6

样例输出:
30
墙壁粉刷
分析:
这是一道动态规划题,我们可以设f[i][j]表示粉刷前i段,并且第i段被粉刷了,而且倒数第2段被粉刷的位置是i-j。那么我们可以得到转移方程为:
F[i][j]=min{f[i-j][k]}+a[i](其中a[i]表示第i个墙壁粉刷的费用,1<=k<=m-j)
这个方程状态量是n*m的,转移是m的,所以时间复杂度为O(n*m*m),因为常数非常小,所以这个动态规划是不会超时的。对于方程中k的选取,是根据每m段中有两端被粉刷而确定的。
最后,还需要注意的就是初始状态,我们需要假定在第0位和第-1位的墙壁已经被粉刷,这样就不需要特殊考虑边界条件了。

ps:这个还没改完,下面的是cbn的代码%%%

#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<cstring>
#include<iostream>
using namespace std;
int n,m;
int a[10005];
int f[10005][105];
int ans=0x3f3f3f3f;
int main()
{
  freopen("brush.in","r",stdin);
  freopen("brush.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    memset(f,0x7f,sizeof f);
    for(int i=2;i<=m;i++)
        for(int j=1;j<i;j++)
        f[i][i-j]=a[i]+a[j];
    for(int i=m+1;i<=n;i++)
        for(int j=i-m+1;j<=i+1;j++)
    {
        for(int k=i-m;k<j;k++)
            f[i][i-j]=min(f[i][i-j],f[j][j-k]);
        f[i][i-j]+=a[i];
    }
    for(int i=n-m+1;i<=n;i++)
        for(int j=i+1;j<=n;j++)
        ans=min(ans,f[j][j-i]);
    printf("%d",ans);
    fclose(stdin);
    fclose(stdout);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
NOIP(全国青少年信息学奥林匹克竞赛)是中国国内最高水平的信息学竞赛之一,是计算机领域的重要赛事。针对NOIP模拟题,通常是为了帮助参赛者熟悉比赛形式和题型,提供足够的训练机会。 数据下载是NOIP比赛中的一个重要环节,因为参赛者需要根据提供的数据集进行程序开发和测试。数据下载一般通过网络进行,参赛者需要在指定的时间段内下载数据集到自己的计算机上。 在进行NOIP模拟题数据下载时,我们可以按照以下步骤进行操作: 1. 确认下载链接:NOIP官方会提供下载数据集的链接或者FTP地址,参赛者需要确认链接是否可用和正确。 2. 选择下载工具:根据自己的需求,参赛者可以选择合适的下载工具进行操作。常见的下载工具有浏览器内置下载工具、迅雷、IDM等,可以根据个人的习惯和需求选择合适的下载工具。 3. 打开下载工具:根据所选择的下载工具类型,打开对应的软件,进入下载界面。 4. 输入下载链接:将NOIP提供的数据集下载链接复制粘贴到下载工具的链接输入框中,点击确定或开始进行下载。 5. 等待下载完成:根据数据集的大小和网络速度不同,下载时间会有所变化。参赛者需要耐心等待下载完成,确保数据集完整地保存到自己的计算机上。 6. 验证数据完整性:下载完成后,参赛者需要验证数据集的完整性,确保所有文件都成功地保存到指定位置。可以进行文件大小的比对或者逐个文件的校验来检查数据完整性。 通过以上步骤,参赛者可以成功地进行NOIP模拟题数据的下载。在实际比赛中,一个高效的数据下载过程可以提高参赛者的准备时间和竞争力,确保能够充分利用所提供的数据集进行开发和测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值