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;
    }
  • 相关阅读:
    Lucene in action 笔记 case study
    关于Restful Web Service的一些理解
    Lucene in action 笔记 analysis篇
    Lucene in action 笔记 index篇
    Lucene in action 笔记 term vector
    Lucene in action 笔记 search篇
    博客园开博记录
    数论(算法概述)
    DIV, IFRAME, Select, Span标签入门
    记一个较困难的SharePoint性能问题的分析和解决
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170305C.html
Copyright © 2011-2022 走看看