• 20200727模拟


    题目

    木材

    会议

    重建

    命名

    wood.cpp

    meeting.cpp

    build.cpp

    内存

    128M

    128M

    128M

    时限

    1s

    1s

    1s

     

    1、木材(wood.cpp(源自洛谷P2440 木材加工

    题目描述

    木材厂有一些原木,现在想把这些木头切割成一些长度相同的小段木头(木头有可能有剩余),需要得到的小段的数目是给定的。当然,我们希望得到的小段木头越长越好,你的任务是计算能够得到的小段木头的最大长度。木头长度的单位是cm。原木的长度都是正整数,我们要求切割得到的小段木头的长度也是正整数。

    例如有两根原木长度分别为11和21,要求切割成到等长的6段,很明显能切割出来的小段木头长度最长为5.

    输入格式

    第一行是两个正整数N和K(1 ≤ N ≤ 100000,1 ≤ K ≤ 100000000),N是原木的数目,K是需要得到的小段的数目。

    接下来的N行,每行有一个1到100000000之间的正整数,表示一根原木的长度。

    输出格式

    能够切割得到的小段的最大长度。如果连1cm长的小段都切不出来,输出”0”。

    输入输出样例

    输入

    3 7

    232

    124

    456

    输出

    114


     

     典型二分

    #include<bits/stdc++.h>
    #define R register int
    #define ll long long
    using namespace std;
    const int N=1e6+5;
    int k,n,a[N];
    ll sum;
    int read()
    {
        int f=1;char ch;
        while((ch=getchar())<'0'||ch>'9')if(ch=='-')f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
        return res*f;
    }
    void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    bool judge(int x)
    {
        int ans=0;
        for(R i=1;i<=n;i++)
        {
            ans+=a[i]/x;
            if(ans>=k)return true;
        }
        return ans>=k;
    }
    int main()
    {
        //freopen("wood.in","r",stdin);
        //freopen("wood.out","w",stdout);
        n=read();k=read();
        for(R i=1;i<=n;i++)
        {
            a[i]=read();
            sum+=a[i];
        }
        int l=0,r=sum/n;//注意这里的r不是a[i]中的最小值
        while(l<r)
        {
            int mid=(l+r+1)>>1;
            if(judge(mid))l=mid;
            else r=mid-1;
        }
        write(l);
        return 0;
    }
    AC代码

     

    2、会议(meeting.cpp(源自洛谷P1395 会议

    题目描述

    有一个村庄居住着n个村民,有n-1条路径使得这n个村民的家联通,每条路径的长度都为1。现在村长希望在某个村民家中召开一场会议,村长希望所有村民到会议地点的距离之和最小,那么村长应该要把会议地点设置在哪个村民的家中,并且这个距离总和最小是多少?若有多个节点都满足条件,则选择节点编号最小的那个点。

    输入格式

    第一行。一个数n,表示有n个村民。

    接下来n-1行,每行两个数字a和b,表示村民a的家和村民b的家之间存在一条路径。

    输出格式

    一行输出两个数字x和y

    x表示村长将会在哪个村民家中举办会议

    y表示距离之和的最小值

    输入输出样例

    输入

    4

    1 2

    2 3

    3 4

    输出

    2 4

    说明/提示

    【数据范围】

    70%数据n<=1000

    100%数据n<=50000


     

     

    #include<bits/stdc++.h>
    #define R register int
    #define ll long long
    using namespace std;
    const int N=1e6+5;
    int n,d[50005],ans,mi=0x3f3f3f3f;
    int read()
    {
        int f=1;char ch;
        while((ch=getchar())<'0'||ch>'9')if(ch=='-')f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
        return res*f;
    }
    void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    int g[1001][1001];
    int main()
    {
        //freopen("meeting.in","r",stdin);
        //freopen("meeting.out","w",stdout);
        
        n=read();
        memset(g,0x3f,sizeof(g));
        for(R i=1;i<n;i++)
        {
            int x=read(),y=read();
            g[x][y]=1;g[y][x]=1;
        }
        for(R k=1;k<=n;k++)
        {
            for(R i=1;i<=n;i++)
            if(i!=k)
            {
                for(R j=1;j<=n;j++)
                if(i!=j&&j!=k)
                {
                    g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
                }
            }
        }
        for(R i=1;i<=n;i++)
        {
            for(R j=1;j<=n;j++)
            if(i!=j)
            {
                d[i]+=g[i][j];
            }
            if(d[i]<mi)
            {
                ans=i;
                mi=d[i];
            }
        }
        write(ans);putchar(' ');write(mi);
        return 0;
    }
    Floyd40分代码
    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    const int N=1e6+5;
    int mi=0x3f3f3f3f;
    int read()
    {
        int f=1;char ch;
        while((ch=getchar())>'9'||ch<'0')if(ch=='-')f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
        return res*f;
    }
    void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    struct node{
        int id,dis;
        bool operator <(const node &a)const
        {
            return dis>a.dis;
        }
    };
    
    int n,head[N],d[N],cnt,k;
    bool v[N];
    struct edge{
        int to,nxt,dis;
    }e[N];
    void add(int a,int b,int w)
    {
        e[++cnt].nxt=head[a];
        e[cnt].to=b;
        e[cnt].dis=w;
        head[a]=cnt;
    }
    void dj(int s)
    {
        priority_queue<node> q;
        memset(d,0x3f,sizeof(d));
        memset(v,false,sizeof(v));
        d[s]=0;q.push((node){s,0});
        while(!q.empty())
        {
            node now=q.top();q.pop();
            if(v[now.id])continue;
            v[now.id]=true;
            for(R i=head[now.id];i;i=e[i].nxt)
            {
                int to=e[i].to;
                if(d[to]>d[now.id]+e[i].dis)
                {
                    d[to]=d[now.id]+e[i].dis;
                    q.push((node){to,d[to]});
                }
            }
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(R i=1;i<n;i++)
        {
            int a,b;scanf("%d%d",&a,&b);
            add(a,b,1);add(b,a,1);
        }
        for(R i=1;i<=n;i++)//没啥好说的,就暴力枚举
        {
            dj(i);
            int ans=0;
            for(int j=1;j<=n;j++)if(i!=j)ans+=d[j];
            if(ans<mi)
            {
                k=i;
                mi=ans;
            }
        }
        write(k);putchar(' ');write(mi);
        return 0;
    }
    优化后的dijkstra70分代码

    正解其实只有关键的一行代码:f[son]=f[fa]+n-2*size[son](详解可见该题解

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    const int N=1e6+5;
    int read()
    {
        int f=1;char ch;
        while((ch=getchar())>'9'||ch<'0')if(ch=='-')f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
        return res*f;
    }
    void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    
    int n,head[N],d[N],cnt,k,size[N],f[N];
    bool v[N];
    struct edge{
        int to,nxt,dis;
    }e[N];
    void add(int a,int b)
    {
        e[++cnt].nxt=head[a];
        e[cnt].to=b;
        head[a]=cnt;
    }
    void build(int x)
    {
        size[x]=1;
        for(R i=head[x];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(d[to])continue;
            d[to]=d[x]+1;
            build(to);
            size[x]+=size[to];
        }
    }
    void dfs(int son,int fa)
    {
        f[son]=f[fa]+n-2*size[son];
        for(R i=head[son];i;i=e[i].nxt)
        {
            int to=e[i].to;
            if(to==fa)continue;
            dfs(to,son);
        }
    }
    int main()
    {
        n=read();
        int k=1,ma=0;
        for(R i=1;i<n;i++)
        {
            int a=read(),b=read();
            add(a,b);add(b,a);
        }
        d[1]=1;build(1);
        for(R i=1;i<=n;i++)ma+=d[i];
        ma-=n;f[1]=ma;
        for(R i=head[1];i;i=e[i].nxt)
        {
            int to=e[i].to;
            dfs(to,1);
        }
        for(R i=2;i<=n;i++)
        {
            if(f[i]<ma)
            {
                ma=f[i];
                k=i;
            }
        }
        write(k);putchar(' ');write(ma);
        return 0;
    }
    AC代码

     

    3、重建(build.cpp(源自洛谷P1119 灾后重建

    题目背景

    B地区在地震过后,所有村庄都造成了一定的损毁,而这场地震却没对公路造成什么影响。但是在村庄重建好之前,所有与未重建完成的村庄的公路均无法通车。换句话说,只有连接着两个重建完成的村庄的公路才能通车,只能到达重建完成的村庄。

    题目描述

    给出B地区的村庄数N,村庄编号从0到N-1,和所有M条公路的长度,公路是双向的。并给出第i个村庄重建完成的时间ti​,你可以认为是同时开始重建并在第ti天重建完成,并且在当天即可通车。若ti为0则说明地震未对此地区造成损坏,一开始就可以通车。之后有Q个询问(x, y, t),对于每个询问你要回答在第t天,从村庄x到村庄的最短路径长度为多少。如果无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未重建完成 ,则需要返回-1。

    输入格式

    第一行包含两个正整数N,M,表示了村庄的数目与公路的数量。

    第二行包含N个非负整数t0, t1,…, tN-1,表示了每个村庄重建完成的时间,数据保证了t0 ≤ t1 ≤ … ≤ tN-1​。

    接下来M行,每行3个非负整数i, j, w,w为不超过10000的正整数,表示了有一条连接村庄i与村庄j的道路,长度为w,保证i≠j,且对于任意一对村庄只会存在一条道路。

    接下来一行也就是M+3行包含一个正整数Q,表示Q个询问。

    接下来Q行,每行3个非负整数x, y, t,询问在第t天,从村庄x到村庄y的最短路径长度为多少,数据保证了t是不下降的。

    输出格式

    共Q行,对每一个询问(x, y, t)输出对应的答案,即在第t天,从村庄x到村庄y的最短路径长度为多少。如果在第t天无法找到从x村庄到y村庄的路径,经过若干个已重建完成的村庄,或者村庄x或村庄y在第t天仍未修复完成,则输出-1。

    输入输出样例

    输入

    4 5

    1 2 3 4

    0 2 1

    2 3 1

    3 1 2

    2 1 4

    0 3 5

    4

    2 0 2

    0 1 2

    0 1 3

    0 1 4

    输出

    -1

    -1

    5

    4

    说明/提示

    对于30%的数据,有N≤50;

    对于30%的数据,有ti= 0,其中有20%的数据有ti = 0且N>50;

    对于50%的数据,有Q≤100;

    对于100%的数据,有N≤200,M≤N×(N-1)/2,Q≤50000,所有输入数据涉及整数均不超过100000。


    啊没想到Floyd竟然是正解!然而我还是改了好几次才A的 555

    #include<bits/stdc++.h>
    #define R register int
    #define ll long long
    using namespace std;
    const int N=1e6+5,inf=0x3f3f3f3f;
    int n,m,q,g[205][205],t[205];
    int read()
    {
        int f=1;char ch;
        while((ch=getchar())<'0'||ch>'9')if(ch=='-')f=-1;
        int res=ch-'0';
        while((ch=getchar())>='0'&&ch<='9')res=res*10+ch-'0';
        return res*f;
    }
    void write(int x)
    {
        if(x<0)
        {
            putchar('-');
            x=-x;
        }
        if(x>9)write(x/10);
        putchar(x%10+'0');
    }
    int main()
    {
        //freopen("build.in","r",stdin);
        //freopen("build.out","w",stdout);
        n=read();m=read();
        memset(g,0x3f,sizeof(g));
        for(R i=0;i<n;i++)t[i]=read();
        for(R i=1;i<=m;i++)
        {
            int x=read(),y=read(),w=read();
            g[x][y]=w;g[y][x]=w;
        }
        q=read();
        int num=0,k=0;
        while(q--)
        {
            
            int x=read(),y=read(),ti=read();
    
            while(t[num]<=ti&&num<n)num++;
            for(;k<num;k++)
            {
                for(R i=0;i<n;i++)
                if(i!=k)
                {
                    for(R j=0;j<n;j++)
                    if(i!=j&&j!=k)
                    {
                        g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
                    }
                }
            }
            if(ti<t[x]||ti<t[y]||g[x][y]>=inf/2)printf("-1
    ");
            else if(x==y)printf("0
    ");
            else write(g[x][y]),putchar('
    ');
        }
        return 0;
    }
    AC代码
  • 相关阅读:
    C++的XML编程经验――LIBXML2库使用指南
    C/C++:sizeof('a')的值为什么不一样?
    Linux core dump file详解
    非阻塞socket的连接
    Java环境设置、HelloWorld例子、Ant环境及运行
    linux下杀死进程命令
    IP协议详解
    内置函数(上)
    异常处理
    递归函数与二分法
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/13395805.html
Copyright © 2020-2023  润新知