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;
}
原文地址:https://www.cnblogs.com/nancheng58/p/10068159.html