zoukankan      html  css  js  c++  java
  • 2017-3-5四校联考

    szy学长出的,除了T3外都比较水 360/400。

    T1.小猪划船

    题目大意:六只猪要过河,三只大猪ABC,三只小猪abc,其中ABCa会划船,共一只船,每次可以载2个人,给出四只猪的划船耗时,每次运载花的时间是船上耗时最小的猪的耗时乘上船上猪的个数,小猪与其对应大猪不在一起时不能与其他大猪在一起,求所有猪到对岸的最小耗时。

    思路:状态最多2^7(每只猪还有船的位置),随便建图最短路或者直接搜索或者构造都能通过该题。我写的O(2^21)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 0x3FFFFFFF
    int g[130][130],t[4],a[6],b;
    bool check()
    {
        if(a[3]!=a[0]&&(a[3]==a[1]||a[3]==a[2]))return false;
        if(a[4]!=a[1]&&(a[4]==a[0]||a[4]==a[2]))return false;
        if(a[5]!=a[2]&&(a[5]==a[0]||a[5]==a[1]))return false;
        return true;
    }
    int hash()
    {
        int r=0,i;
        for(i=0;i<6;++i)r|=(a[i]<<i);
        return r|(b<<6);
    }
    int main()
    {
        freopen("boat.in","r",stdin);
        freopen("boat.out","w",stdout);    
        int i,j,k,x;
        for(i=0;i<4;++i)scanf("%d",&t[i]);
        for(i=0;i<1<<7;++i)for(j=0;j<1<<7;++j)if(i!=j)g[i][j]=INF;
        for(i=0;i<1<<7;++i)
        {
            for(j=0;j<6;++j)a[j]=bool(i&(1<<j));b=bool(i&(1<<6));
            if(!check())continue;
            for(j=0;j<4;++j)if(a[j]==b)
            {
                a[j]^=1;b^=1;
                if(check())x=hash(),g[i][x]=min(g[i][x],t[j]);
                a[j]^=1;b^=1;
                for(k=0;k<6;++k)if(j!=k&&a[k]==b)
                {
                    if(j==3&&(k==1||k==2))continue;
                    a[j]^=1;a[k]^=1;b^=1;
                    if(check())x=hash(),g[i][x]=min(g[i][x],t[j]<<1);
                    a[j]^=1;a[k]^=1;b^=1;
                }
            }
        }
        for(k=0;k<1<<7;++k)for(i=0;i<1<<7;++i)for(j=0;j<1<<7;++j)
            g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
        printf("%d",g[0][127]);
        fclose(stdin);fclose(stdout);return 0;
    }

    T2.小猪星球

    题目大意:给出N个点M条边的图,边权可能为负数,可以一次把所有边的边权加上同一个数,求出1到n非负的最短路。(N<=100,M<=N(N+1)/2)

    思路:以前的原题。二分加上多少,SPFA check。

    #include<cstdio>
    #include<cstring>
    #define MN 100
    #define ME 5050
    #define INF 100000
    struct edge{int nx,t,w;}e[ME*2+5];
    int h[MN+5],rh[MN+5],en,u[MN+5],q[MN+5],qn,d[MN+5],z[MN+5];
    void ins(int*h,int x,int y,int w){e[++en]=(edge){h[x],y,w};h[x]=en;}
    int spfa(int x,int c)
    {
        if(z[x])return 1;z[x]=1;
        for(int i=h[x];i;i=e[i].nx)if(u[e[i].t]&&d[x]+e[i].w+c<d[e[i].t])
            {d[e[i].t]=d[x]+e[i].w+c;if(spfa(e[i].t,c))return 1;}
        return z[x]=0;
    }
    bool check(int x)
    {
        memset(d,42,sizeof(d));
        memset(z,d[1]=0,sizeof(z));
        return !spfa(1,x);
    }
    int main()
    {
        freopen("planet.in","r",stdin);
        freopen("planet.out","w",stdout);
        int T,n,m,x,y,w,i,j,l,r,mid,ans;
        for(scanf("%d",&T);T--;)
        {
            scanf("%d%d",&n,&m);
            memset(h,en=0,sizeof(h));memset(rh,0,sizeof(rh));
            while(m--)
            {
                scanf("%d%d%d",&x,&y,&w);
                ins(h,x,y,w);ins(rh,y,x,w);
            }
            memset(u,0,sizeof(u));
            for(u[q[i=qn=0]=n]=1;i<=qn;++i)
                for(j=rh[q[i]];j;j=e[j].nx)if(!u[e[j].t])u[q[++qn]=e[j].t]=1;
            if(!u[1]){puts("-1");continue;}
            for(l=-INF,r=INF;l<=r;)
                if(check(mid=l+r>>1)&&d[n]>=0)r=mid-1,ans=d[n];
                else l=mid+1;
            printf("%d
    ",ans);
        }
        fclose(stdin);fclose(stdout);return 0;
    }

    T3.小猪送货

    题目大意:N个点,源到点i连一条流量pi的边,点i到汇连流量si的边,对所有i<j的i和j连流量c的单向边,求最大流。(N<=10000)

    思路:CF原题。暴力60分。考虑转成最小割DP,由于点与点之间边的流量相同,可以用f[i][j]表示前i个点j个割S,i-j个割T的最小割,可以得到DP方程f[j]=min(f[j]+p[i]+c*j,f[j-1]+s[i]),复杂度O(n^2)。

    暴力

    #include<cstdio>
    #include<cstring>
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100
    #define ME 5150
    #define S MN+1
    #define T MN+2
    #define INF 0x7FFFFFFF
    struct edge{int nx,t,w;}e[ME*2+5];
    int h[MN+5],en=1,d[MN+5],q[MN+5],qn,c[MN+5];
    long long ans;
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    bool bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
            if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    int dfs(int x,int r)
    {
        if(x==T)return r;
        int u=0,k;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[e[i].t]==d[x]+1)
        {
            k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(u==r)return r;
        }
        return d[x]=0,u;
    }
    int main()
    {
        freopen("deliver.in","r",stdin);
        freopen("deliver.out","w",stdout);
        int n=read(),c=read(),i,j;
        for(i=1;i<=n;++i)ins(S,i,read());
        for(i=1;i<=n;++i)ins(i,T,read());
        for(i=1;i<n;++i)for(j=i+1;j<=n;++j)ins(i,j,c);
        while(bfs())ans+=dfs(S,INF);
        printf("%I64d",ans);
        fclose(stdin);fclose(stdout);return 0;
    }
    View Code

    正解

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #include<vector>
    #define MN 10000
    #define INF (1LL<<60)
    int a[MN+5],b[MN+5];
    ll f[MN+5],ans=INF;
    int main()
    {
        int n=read(),c=read(),i,j;
        for(i=1;i<=n;++i)a[i]=read();
        for(i=1;i<=n;++i)b[i]=read();
        for(i=1;i<=n;++i)for(j=i;j>=0;--j)
            f[j]=min(j<i?f[j]+a[i]+(ll)c*j:INF,j?f[j-1]+b[i]:INF);
        for(i=0;i<=n;++i)ans=min(ans,f[i]);
        printf("%I64d",ans);
    }

    T4.小猪数数

    题目大意:两个人玩游戏,一开始各有一个1,每次可以选择一个玩家,让他的数加上对方的数,给出N,M,问最少进行几轮游戏到达当前局面,不可能则输出-1。(N,M在long long范围内)

    思路:若n>m,则n只能是由n-m加上m得到的,故可以用求gcd的辗转相除法处理,若求出的gcd不为1则输出-1,另外数据可能有0或负数,要特判……复杂度O(logN+logM)。

    #include<cstdio>
    #define ll long long
    ll a,b,ans;
    ll gcd(ll a,ll b){return b?(ans+=a/b,gcd(b,a%b)):a;}
    int main()
    {
        freopen("math.in","r",stdin);
        freopen("math.out","w",stdout);
        scanf("%I64d%I64d",&a,&b);
        if(a<1||b<1||gcd(a,b)!=1)puts("-1");
        else printf("%I64d",ans-1);
        fclose(stdin);fclose(stdout);return 0;
    }
  • 相关阅读:
    SpatiePermissionPermissionServiceProvider' not found
    ThinkPad L14G 连接外接显示屏无响应问题解决
    HBase 初学习之数据模型
    python 实现 kakfa 的 生产消费模式 和 发布订阅模式
    数据结构中树的基本概念
    MySQL行级锁、表级锁、页级锁详细介绍
    设置div只显示2行
    linux 关闭防护墙,永久关闭
    yum install nginx 时报错:No package nginx available.
    win10 查询端口,杀掉端口进程
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170305C.html
Copyright © 2011-2022 走看看