zoukankan      html  css  js  c++  java
  • Qbxt 模拟赛&&day-8

    /*
    今天的题目还是比较不错的.
    今天考的很烂还是依旧的弱.
    快考试了加油吧.
    Bless all.
    */
    注:所有题目的时间限制均为 1s,内存限制均为 256MB。
    1.第K小数 (number.cpp/c/pas)
    【问题描述】
    有两个正整数数列,元素个数分别为N和M。从两个数列中分别任取一个数 相乘,这样一共可以得到N*M个数,询问这N*M个数中第K小数是多少。
    【输入格式】
    输入文件名为number.in。
    输入文件包含三行。
    第一行为三个正整数N,M和K。
    第二行为N个正整数,表示第一个数列。
    第三行为M个正整数,表述第二个数列。
    【输出格式】
    输出文件名为number.out。
    输出文件包含一行,一个正整数表示第K小数。
    【输入输出样例1】
    number.in
    2 3 4
    1 2
    2 1 3
    number.out  
    3
    【输入输出样例2】
    number.in
    5 5 18
    7 2 3 5 8
    3 1 3 2 5
    number.out  
    16
    【数据规模与约定】
    ![这里写图片描述](https://img-blog.csdn.net/20161110205658499)
    ![这里写图片描述](https://img-blog.csdn.net/20161110205712476)
    
    /*
    二分答案.
    O((n+m)logk). 
    然而本蒟蒻一开始只能暴力.
    其实一开始也想到这个单调性了.
    但想了想ans并不单调啊.
    然后就跪了orz.
    二分找下界.
    检验的时候因为确定了一个序列之后
    另一个序列的元素就单调了.
    so 我们二分一个答案
    就可以计算出比它小的数的个数.
    这个显然是单调的.
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #define MAXM 25000001
    #define MAXN 200001
    #define LL long long
    using namespace std;
    LL n,m,k;
    LL a[MAXN],b[MAXN],tot,ans;
    LL read()
    {
        LL 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-48,ch=getchar();
        return x*f;
    }
    bool check(LL x)
    {
        int p=m;tot=0;
        for(int i=1;i<=n;i++)
        {
            while(p&&a[i]*b[p]>=x) p--;
            tot+=p;
        }
        if(tot>=k) return true;
        return false;
    }
    inline void erfen(LL l,LL r)
    {
        LL mid;
        while(l+1<r)
        {
            mid=(l+r)>>1;
            if(check(mid)) ans=mid,r=mid;
            else l=mid;
        }
        cout<<l;
    }
    int main()
    {
        freopen("number.in","r",stdin);
        freopen("number.out","w",stdout);
        n=read(),m=read(),k=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=m;i++) b[i]=read();
        sort(a+1,a+n+1),sort(b+1,b+m+1);
        erfen(0,a[n]*b[m]);
        return 0;
    }

    2. dwarf tower (dwarf.cpp/c/pas)
    【问题描述】
    Vasya在玩一个叫做”Dwarf Tower”的游戏,这个游戏中有n个不同的物品, 它们的编号为1到n。现在Vasya想得到编号为1的物品。 获得一个物品有两种方式:
    1. 直接购买该物品,第i件物品花费的钱为ci
    2. 用两件其他物品合成所需的物品,一共有m种合成方式。
    请帮助Vasya用最少的钱获得编号为1的物品。
    【输入格式】
    第一行有两个整数n,m(1<=n<=10000,0<=m<=100000),分别表示有n种物品以 及m种合成方式。
    接下来一行有n个整数,第i个整数ci表示第i个物品的购买价格,其中 0<=ci<=10^9。
    接下来m行,每行3个整数ai,xi,yi,表示用物品xi和yi可以合成物品ai,其 中(1<=ai,xi,yi<=n; ai<>xi, xi<>yi, yi<>ai)
    【输出格式】
    一行,一个整数表示获取物品 1 的最少花费。
    输入样例:
    5 3
    5 0 1 2 5
    5 2 3
    4 2 3
    1 4 5
    输出样例:
    2
    【数据规模与约定】
    60%的数据, n<=100
    100%的数据, n<=10000, m<=100000

    /*
    75.
    愚蠢的我建了一棵树.
    还能自动判环2333.
    但不知道为什么会W.
    望路过大神指教. 
    */
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #define MAXN 10001
    using namespace std;
    int w[MAXN],n,m,f[MAXN];
    vector<int>son[MAXN];
    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-48,ch=getchar();
        return x*f;
    }
    inline int slove(int u)
    {
        if(f[u]) return f[u];
        f[u]=w[u];
        for(int i=0;i<son[u].size();i+=2)
          f[u]=min(w[u],slove(son[u][i])+slove(son[u][i+1]));
        return f[u];
    }
    int main()
    {
        freopen("dwarf.in","r",stdin);
        freopen("dwarf.out","w",stdout);
        int x,y,z;
        n=read(),m=read();
        for(int i=1;i<=n;i++) w[i]=read();
        if(!m)
        {
            printf("%d",w[1]);
            return 0;
        }
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(),z=read();
            son[x].push_back(y),son[x].push_back(z);
        }
        cout<<slove(1);
        return 0;
    }
    /*
    spfa松弛.
    一开始也想这样做来着.
    但是建图的时候傻眼了.
    其实三个点的话就那两个点作为(u,v).
    另一个点辅助更新就好了.
    一开始让所有点都入队
    是为了保证能够正确松弛.
    */
    #include<iostream>
    #include<cstdio>
    #include<queue>
    #define MAXN 10001
    using namespace std;
    int n,m,dis[MAXN],head[MAXN],cut;
    bool b[MAXN];
    queue<int>q;
    struct data{int v,next,x;}e[MAXN*20];
    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-48,ch=getchar();
        return x*f;
    }
    inline void add(int v,int u,int x)
    {
        e[++cut].v=v;
        e[cut].next=head[u];
        e[cut].x=x;
        head[u]=cut;
    }
    inline void bfs()
    {
        int u;
        for(int i=1;i<=n;i++) b[i]=true;
        while(!q.empty())
        {
            u=q.front();q.pop();b[u]=false;
            for(int i=head[u];i;i=e[i].next)
            {
                int v=e[i].v,x=e[i].x;
                if(dis[v]>dis[x]+dis[u])
                {
                    dis[v]=dis[x]+dis[u];
                    if(!b[v]) b[v]=true,q.push(v);
                }
            }
        }
    }
    int main()
    {
        freopen("dwarf.in","r",stdin);
        freopen("dwarf.out","w",stdout);
        int x,y,z;
        n=read(),m=read();
        for(int i=1;i<=n;i++) dis[i]=read(),q.push(i);
        if(!m)
        {
            printf("%d",dis[1]);
            return 0;
        }
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(),z=read();
            add(x,y,z),add(x,z,y);
        }
        bfs();
        printf("%d",dis[1]);
        return 0;
    }

    3. abcd (abcd.cpp/c/pas)
    【问题描述】
    有4个长度为N的数组a,b,c,d。现在需要你选择N个数构成数组e,数组e满足 a[i]≤e[i]≤b[i]以及这里写图片描述
    并且使得这里写图片描述最大。
    【输入格式】
    输入文件名为abcd.in。
    输入文件共 N+1 行。
    第 1 行包含1个正整数N。
    第 i+1 行包含4个整数a[i],b[i],c[i],d[i]。
    【输出格式】
    输出文件名为abcd.out。
    输出共1行,包含1个整数,表示所给出公式的最大值。
    输入数据保证一定有 解。
    【输入输出样例1】
    abcd.in
    5
    - 1 1 2 5
    -2 2 1 2
    0 1 1 3
    -2 -1 3 10
    -2 2 3 9
    abcd.out
    2
    【输入输出样例2】
    abcd.in
    10
    1 10 1 7
    -10 10 2 0
    -10 10 2 2
    -10 10 2 0
    1 10 1 0
    -10 10 2 0
    10 10 2 0
    1 10 1 0
    -10 10 2 0
    1 10 1 0
    abcd.out
    90
    【输入输出样例3】
    abcd.in
    10
    1 10 1 0
    -10 10 2 2
    -10 10 2 2
    -10 10 2 2
    1 10 1 0
    -10 10 2 2
    -10 10 2 2
    1 10 1 0
    -10 10 2 2
    1 10 1 0
    abcd.out
    -4
    【数据规模与约定】
    对于 20%的数据, N≤10, -2≤a[i]

    /*
    20.
    纯暴力(剪枝忽视掉). 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<ctime>
    #define MAXN 201
    using namespace std;
    int a[MAXN],b[MAXN],c[MAXN],d[MAXN],n,ans=-1e9,tot,s[MAXN];
    int sum1[MAXN],sum2[MAXN];
    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-48,ch=getchar();
        return x*f;
    }
    inline void dfs(int t,int tot,int sum)
    {
        if(t==n+1)
        {
            if(!tot) 
            ans=max(ans,sum);
            return ;
        }
        for(int i=b[t];i>=a[t];i--)
        {
            if(tot+i*c[t]+sum1[t+1]<0) continue;
            dfs(t+1,tot+i*c[t],sum+i*d[t]);
        }
        return ;
    }
    int main()
    {
        freopen("abcd.in","r",stdin);
        freopen("abcd.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)
          a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read();
        for(int i=n;i>=1;i--) sum1[i]=sum1[i+1]+b[i]*c[i];
        dfs(1,0,0);
        printf("%d",ans);
        return 0;
    }
    /*
    60.
    f[i][y]表示从n到i构成y的最大值.
    从1点跑固定终点的单源DAG.
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<ctime>
    #define MAXN 202
    #define MAXM 100001
    using namespace std;
    int a[MAXN],b[MAXN],c[MAXN],d[MAXN],n,tot;
    int sum1[MAXN],sum2[MAXN],f[MAXN][MAXM*2+100],INF;
    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-48,ch=getchar();
        return x*f;
    }
    inline int dfs(int t,int tot)
    {
        if(f[t][tot]!=INF) return f[t][tot];
        if(t==n+1)
        {
            if(tot==MAXM-1) return 0;
            return INF;
        }
        for(int i=b[t];i>=a[t];i--)
        {
            //if(tot+i*c[t]+sum1[t+1]<0) continue;
            f[t][tot]=max(f[t][tot],dfs(t+1,tot+i*c[t])+i*d[t]);
        }
        return f[t][tot];
    }
    int main()
    {
        freopen("abcd.in","r",stdin);
        freopen("abcd.out","w",stdout);
        memset(f,-127/3,sizeof f);INF=f[0][0];
        n=read();
        for(int i=1;i<=n;i++)
          a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read();
        //for(int i=n;i>=1;i--) sum1[i]=sum1[i+1]+b[i]*c[i];
        printf("%d",dfs(1,MAXM-1));
        return 0;
    }
    /*
    正解多重背包.
    想不到吖想不到.
    对于∑e[i]*c[i]=0 ①
    和ans=∑b[i]*e[i] ②
    因为e[i]=[a[i],b[i]]等价于[0,b[i]-a[i]]+a[i];
    so 问题转化为使得
    ∑(b[i]-a[i])*c[i]+∑a[i]*c[i]=0
    且∑(b[i]-a[i])*d[i]+∑a[i]*d[i]最大.
    然后∑a[i]*c[i]和∑a[i]*d[i]是可以计算的.
    令V=∑a[i]*c[i](V<0),s[i]=b[i]-a[i].
    so 问题转化为在体积为-V的背包中取物品s[i]求最大值.
    可以从1(or n)跑固定起点和终点的DAG
    or二进制拆01背包or四边形单调队列等等...
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MAXN 201
    #define MAXM 100001
    using namespace std;
    int n,a[MAXN],b[MAXN],c[MAXN],d[MAXN];
    int V,ans1,tot,w[MAXM],v[MAXM],f[MAXM];
    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-48,ch=getchar();
        return x*f;
    }
    inline int slove()
    {
        V*=-1;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=b[i];j<<=1)
              b[i]-=j,w[++tot]=d[i]*j,v[tot]=c[i]*j;
            if(b[i]) w[++tot]=d[i]*b[i],v[tot]=c[i]*b[i];
        }
        f[0]=0;
        for(int i=1;i<=tot;i++)
          for(int j=V;j>=v[i];j--)
            f[j]=max(f[j],f[j-v[i]]+w[i]);
        return f[V];
    }
    int main()
    {
        freopen("abcd.in","r",stdin);
        freopen("abcd.out","w",stdout);
        n=read();memset(f,-127/3,sizeof f);
        for(int i=1;i<=n;i++)
          a[i]=read(),b[i]=read(),c[i]=read(),d[i]=read(),
        V+=a[i]*c[i],b[i]-=a[i],ans1+=a[i]*d[i];
        printf("%d",slove()+ans1);
        return 0;
    }
  • 相关阅读:
    bzoj1415 NOI2005聪聪和可可
    Tyvj1952 Easy
    poj2096 Collecting Bugs
    COGS 1489玩纸牌
    COGS1487 麻球繁衍
    cf 261B.Maxim and Restaurant
    cf 223B.Two Strings
    cf 609E.Minimum spanning tree for each edge
    cf 187B.AlgoRace
    cf 760B.Frodo and pillows
  • 原文地址:https://www.cnblogs.com/nancheng58/p/10068159.html
Copyright © 2011-2022 走看看