zoukankan      html  css  js  c++  java
  • NOIP 2018 day1 题解

      今年noip的题和去年绝对是比较坑的题了,但是打好的话就算是普通水准也能350分以上吧。

    t1:

    很显然这是一个简单的dp即可。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<ctime>
    #include<iomanip>
    #include<vector>
    #include<map>
    #include<queue>
    #include<stack>
    using namespace std;
    inline long long read()
    {
        long long 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;
    }
    const long long maxn=100020;
    long long n;
    long long a[maxn],now=0,ans=0;
    int main()
    {
        //freopen("road.in","r",stdin);
        //freopen("road.out","w",stdout);
        n=read();
        for(long long i=1;i<=n;i++)a[i]=read();
        for(long long i=1;i<=n;i++)
        {
            if(a[i]>now){ans+=a[i]-now;now=a[i];}
            else now=a[i];
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code

    t2:

    很显然,这是个完全背包,考试的时候沙比没看出来打了搜索。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<ctime>
    #include<iomanip>
    #include<vector>
    #include<map>
    #include<queue>
    #include<stack>
    using namespace std;
    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;
    }
    const int maxn=200;
    int t,n;
    int a[maxn],f[25002],ans=0;
    int main()
    {
        //freopen("1.in","r",stdin);
        //freopen("money.out","w",stdout);
        t=read();
        for(int u=1;u<=t;u++)
        {
            memset(f,0,sizeof(f));
            n=read();f[0]=1;ans=0;
            for(int i=1;i<=n;i++)a[i]=read();
            for(int i=1;i<=n;i++)
                for(int j=a[i];j<=25001;j++)
                        f[j]+=f[j-a[i]];
            for(int i=1;i<=n;i++)if(f[a[i]]==1)ans++;
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

    暴力55分代码如下:

    #include<bits/stdc++.h>
    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<deque>
    #include<bitset>
    #include<set>
    #include<vector>
    #include<algorithm>
    #include<stack>
    #include<map>
    #include<iomanip>
    using namespace std;
    inline long long read()
    {
        long long 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 void put(long long x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        long long num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const long long maxn=50002;
    long long n,m,flag=1,flag1=2;
    long long lin[maxn<<1],nex[maxn<<1],ver[maxn<<1],e[maxn<<1],len=0;
    long long ru[maxn],s,ans=0,q[maxn<<2],h=0,t=0,vis[maxn<<1];
    long long d[maxn],cnt=0,u;
    void add(long long x,long long y,long long z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    //赛道修建 55分做法
    long long check1(long long x)
    {
        t=0;h=0;
        long long tot=0,num=0;
        q[++t]=s;
        memset(vis,0,sizeof(vis));
        vis[s]=1;
        //cout<<x<<endl;
        while(h++<t)
        {
            long long te=q[h];
            for(long long i=lin[te];i;i=nex[i])
            {
                long long tn=ver[i];
                if(vis[tn]==1)continue;
                q[++t]=tn;
                num+=e[i];
                vis[tn]=1;
                if(num>=x)tot++,num=0;
            }
        }
        if(tot>=m)return 1;
        else return 0;
    }
    void solve1()//一条链
    {
        for(long long i=1;i<=n;i++)if(ru[i]==1){s=i;break;}
        //cout<<s<<endl;
        //cout<<m<<endl;
        //cout<<ans<<endl;
        long long l=1,r=ans;
        while(l+1<r)
        {
            long long mid=(l+r)>>1;
            if(check1(mid)==1)l=mid;
            else r=mid;
        }
        if(check1(r)==1)put(r);
        else put(l);
        return;
    }
    void dp(long long x)
    {    
        vis[x]=1;
        for(long long i=lin[x];i;i=nex[i])
        {
            long long tn=ver[i];
            if(vis[tn]==1)continue;
            dp(tn);
            cnt=max(cnt,d[x]+d[tn]+e[i]);
            d[x]=max(d[x],d[tn]+e[i]);
        }
        return;
    }
    void bfs()
    {
        h=0,t=0;cnt=0;
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        q[++t]=1;vis[1]=1;
        while(h++<t)
        {
            long long te=q[h];
            for(long long i=lin[te];i;i=nex[i])
            {
                long long tn=ver[i];
                if(vis[tn]==1)continue;
                d[tn]=max(d[tn],d[te]+e[i]);//取max更加严谨,尽管更慢
                if(d[tn]>cnt)cnt=d[tn],u=tn;
                q[++t]=tn;vis[tn]=1;
            }
        }
        //cout<<u<<endl;
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        h=0,t=0;cnt=0;
        q[++t]=u;vis[u]=1;
        //cout<<u<<endl;
        while(h++<t)
        {
            long long te=q[h];
            for(long long i=lin[te];i;i=nex[i])
            {
                long long tn=ver[i];
                if(vis[tn]==1)continue;
                d[tn]=max(d[tn],d[te]+e[i]);//取max更加严谨,尽管更慢
                if(d[tn]>cnt)cnt=d[tn];
                q[++t]=tn;vis[tn]=1;
            }
        }
        put(cnt);return;
    }
    void dfs(int x)
    {
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(vis[tn]==1)continue;
            vis[tn]=1;
            d[tn]=max(d[tn],d[x]+e[i]);
            if(d[tn]>cnt)cnt=d[tn],u=tn;
            dfs(tn);
        }
    }
    int check2(int x)
    {
        cnt=0;int j=t+1;//双指针
        for(int i=1;i<=t;i++)if(q[i]>=x){j=i;break;}
        cnt+=t-j+1;j--;
        for(int i=1;i<j;i++)if(q[i]+q[j]>=x)j--,cnt++;
        if(cnt>=m)return 1;
        return 0;
    }
    void solve2()//菊花图
    {
        h=0,t=0;
        for(int i=lin[1];i;i=nex[i])q[++t]=e[i];
        sort(q+1,q+1+t);
        //cout<<ans<<endl;
        //for(int i=1;i<=t;i++)cout<<q[i]<<endl;
        int l=1,r=ans;
        while(l+1<r)
        {
            int mid=(l+r)>>1;
            if(check2(mid)==1)l=mid;
            else r=mid;
        }
        if(check2(r)==1)put(r);
        else put(l);return;
    }
    void solve3()
    {
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        dp(1);put(cnt);//树形dp求树的直径
        //bfs();//两次bfs求树的直径
        //两次dfs求树的直径
        /*memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        cnt=0;vis[1]=1;dfs(1);
        memset(vis,0,sizeof(vis));
        memset(d,0,sizeof(d));
        cnt=0;vis[u]=1;dfs(u);
        put(cnt);*/
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(long long i=1;i<n;i++)
        {
            long long x,y,z;
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
            if(x+1!=y)flag=0;//一条链的情况
            ru[x]++;ru[y]++;
            ans+=z;
            if(x!=1)flag1=0;
        }
        //cout<<flag1<<endl;
        if(flag==1){solve1();return 0;}//一条链
        if(flag1==2){solve2();return 0;}//菊花图
        if(m==1){solve3();return 0;}//求树的直径的情况,两遍bfs或树形dp
        return 0;
    }

    55分很好写,一个直径一个二分一个双指针扫描。

    可是考试的时候打了一个n^n的暴力。菜死了

    正解是二分+树形dp+二分(二分的边界很重要要不卡死)

    #include<iomanip>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<deque>
    #include<bitset>
    #include<set>
    #include<vector>
    #include<algorithm>
    #include<stack>
    #include<map>
    #include<iomanip>
    using namespace std;
    inline long long read()
    {
        long long 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 void put(long long x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        long long num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const long long maxn=50002;
    long long n,m;
    long long lin[maxn<<1],nex[maxn<<1],ver[maxn<<1],e[maxn<<1],len=0;
    int ans=0,u=0,cnt=0;
    int f[maxn],v[maxn];//f[i]表示以i为根节点所能拼成最多的道路。
    int q[maxn<<2],t=0;
    //v[i]表示当前节点还剩下的最长链
    void add(long long x,long long y,long long z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    //赛道修建100分做法-->>树形dp
    int check1(int x,int p)
    {
        int sum=0;
        for(int i=1,j=t;i<j;i++)
        {
            if(i==x)continue;
            if(j==x)j--;
            if(q[i]+q[j]>=p)sum++,j--;
        }
        if(sum>=u)return 1;
        return 0;
    }
    void dp(int x,int p,int fa)
    {
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(tn==fa)continue;
            dp(tn,p,x);
        }
        t=0,u=0;;cnt=0;
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(tn==fa)continue;
            f[x]+=f[tn];
            if(e[i]+v[tn]>=p){cnt++;continue;}
            q[++t]=e[i]+v[tn];
        }
        sort(q+1,q+1+t);
        for(int i=1,j=t;i<j;i++)if(q[i]+q[j]>=p)u++,j--;
        int l=0,r=t;//再次二分枚举哪条边不用来更新v[x]
        while(l+1<r)
        {
            int mid=(l+r)>>1;
            if(check1(mid,p)==1)l=mid;
            else r=mid;
        }
        if(check1(r,p)==1)v[x]=q[r];
        else v[x]=q[l];
        f[x]+=cnt+u;
    }
    int check(int x)
    {
        memset(f,0,sizeof(f));
        memset(v,0,sizeof(v));
        dp(1,x,0);
        if(f[1]>=m)return 1;
        else return 0;
    }
    void wy()//闻道玉门犹被遮
    {
        int l=1,r=ans;
        while(l+1<r)//二分枚举当前修建的道路长度
        {
            int mid=(l+r)>>1;
            if(check(mid)==1)l=mid;
            else r=mid;
        }
        if(check(r)==1)put(r);
        else put(l);
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<n;i++)
        {
            int x,y,z;
            x=read();y=read();z=read();
            add(x,y,z);add(y,x,z);
            ans+=z;
        }
        wy();//应将性命逐轻车
        return 0;
    }

    就这样没了 300分很简单。

  • 相关阅读:
    判断是否可以点击
    窗口截图
    设置等待操作
    时间控件处理
    eclipse小技巧
    Angular 学习1
    MVC 中引用Angularjs
    Bootstrap 侧边栏 导航栏
    C# 直接使用sql语句对数据库操作 (cmd.ExecuteNonQuery)
    sql 常用的语句(sql 创建表结构 修改列 清空表)
  • 原文地址:https://www.cnblogs.com/chdy/p/10136484.html
Copyright © 2011-2022 走看看