• 2017-4-7校内训练


    丧病hzwer的ctsc训练赛 My AC:3/4

    A.[Ctsc2014]企鹅QQ

    思路:乱hash,我比较菜,写的丑代码各种WA+TLE,好久才A掉。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define MN 200
    #define MX 6000000
    #define MM 9000001
    #define MOD1 890123798112473LL
    struct map
    {
        struct edge{int nx,t;ll x;}e[MX+5];
        int h[MM],en;
        inline int&operator[](ll x)
        {
            int p=(x%MM+MM)%MM;
            for(int i=h[p];i;i=e[i].nx)if(e[i].x==x)return e[i].t;
            e[++en]=(edge){h[p],0,x};h[p]=en;
            return e[en].t;
        }
    }mp1,mp2;
    char s[MN+5];
    ll f1[MN+5],f2[MN+5];
    int main()
    {
        int n,m,k,i,ans=0;ll h1,h2;
        scanf("%d%d%d",&n,&m,&k);
        while(n--)
        {
            scanf("%s",s+1);
            for(i=m;i;--i)f1[i]=(f1[i+1]*31^(s[i]+23))%MOD1,
                          f2[i]=(f2[i+1]*37^(s[i]+23));
            for(i=1,h1=h2=0;i<=m;++i)
            {
                ans+=min(mp1[h1*23333^f1[i+1]]++,mp2[h2*23333^f2[i+1]]++);
                h1=(h1*37+s[i])%MOD1;h2=(h2*31+s[i]);
            }
        }
        printf("%d",ans);
    }

    B.[CTSC2007]数据备份Backup

    思路:显然只有相邻的会被选,先把所有相邻线段用链表链起来塞到堆里,每次取出最小的,与他相邻的线段暂时不能选就删掉,如果要在之后再选相邻的这两条,显然不可能只选其中一条而不选中间这条,我们把这三条合并成左+右-中再塞回堆即可。

    #include<cstdio>
    #include<queue>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 100000
    int a[MN+5],l[MN+5],r[MN+5],w[MN+5],u[MN+5];
    class cmp{public:bool operator()(int a,int b){return w[a]>w[b];}};
    priority_queue<int,vector<int>,cmp> pq;
    int main()
    {
        int n,k,i,x,ans=0;
        n=read();k=read();
        for(i=1;i<=n;++i)a[i]=read();
        w[0]=w[n]=1e9;
        for(i=1;i<n;++i)l[i]=i-1,r[i]=i+1,w[i]=a[i+1]-a[i],pq.push(i);
        for(i=0;i<k;++i)
        {
            do x=pq.top(),pq.pop();while(u[x]);
            ans+=w[x];
            w[x]=w[l[x]]+w[r[x]]-w[x];
            u[l[x]]=u[r[x]]=1;
            l[x]=l[l[x]];r[x]=r[r[x]];
            pq.push(r[l[x]]=l[r[x]]=x);
        }
        printf("%d",ans);
    }

    C.[Ctsc2015]misc

    思路:枚举s,每个s先跑一遍单源最短路,只考虑最短路上的边(即满足dis[u]+len=dis[v]的边),得到一张拓扑图,在拓扑图上先dp出s到每个点的最短路宽度$sigma_{st}$

    考虑每个v,$R(v)=sum frac{a_{s}a_{t}sigma_{st}(v)}{sigma{st}}=sum frac{a_{s}a_{t}sigma_{sv}sigma_{vt}}{sigma{st}}=a_{s}sigma_{sv}sumfrac{a_{t}sigma_{vt}}{sigma_{st}}$,其中t为v在最短路拓扑图中能到的点。

    我们令$f(v)=sumfrac{a_{t}sigma_{vt}}{sigma_{st}}$,则有$f(u)=sum c_{j}(frac{a_{v}}{sigma_{sv}}+f(v))$,其中j为u到v的一条最短路边。然后DP下就做完了。

    #include<cstdio>
    #include<cstring>
    #define MN 1000
    #define MM 4000
    #define N 1024
    #define lb long double
    struct edge{int nx,t,w;lb c;}e[MM*2+5];
    int n,h[MN+5],en,a[MN+5],d[MN+5],q[MN+5],qn,r[MN+5];
    lb fk[MN+5],fj[MN+5],ans[MN+5];
    inline void ins(int x,int y,int w,lb c)
    {
        e[++en]=(edge){h[x],y,w,c};h[x]=en;
        e[++en]=(edge){h[y],x,w,c};h[y]=en;
    }
    struct data{int x,f;}t[N*2+5];
    data min(data a,data b){return a.x<b.x?a:b;}
    void change(int k,int x){for(t[k+=N].x=x;k>>=1;)t[k]=min(t[k<<1],t[k<<1|1]);}
    void dj(int s)
    {
        memset(d,127,sizeof(d));
        memset(t,127,sizeof(t));
        for(int i=1;i<=n;++i)t[i+N].f=i;
        for(change(s,d[s]=0);t[1].x<d[0];change(t[1].f,d[0]))
            for(int i=h[t[1].f];i;i=e[i].nx)if(d[t[1].f]+e[i].w<d[e[i].t])
                change(e[i].t,d[e[i].t]=d[t[1].f]+e[i].w);
    }
    void pre()
    {
        int i,j;
        memset(r,0,sizeof(r));
        for(i=1;i<=n;++i)for(j=h[i];j;j=e[j].nx)
            if(d[i]+e[j].w==d[e[j].t])++r[e[j].t];
        for(i=1,qn=0;i<=n;++i)if(!r[i])q[++qn]=i;
        for(i=1;i<=qn;++i)
        {
            fk[q[i]]=i<2;
            for(j=h[q[i]];j;j=e[j].nx)
            {
                if(d[e[j].t]+e[j].w==d[q[i]])fk[q[i]]+=fk[e[j].t]*e[j].c;
                if(d[q[i]]+e[j].w==d[e[j].t]&&!--r[e[j].t])q[++qn]=e[j].t;
            }
        }
    }
    void solve(int s)
    {
        int i,j;
        memset(r,0,sizeof(r));
        for(i=1;i<=n;++i)for(j=h[i];j;j=e[j].nx)
            if(d[i]+e[j].w==d[e[j].t])++r[i];
        for(i=1,qn=0;i<=n;++i)if(!r[i])q[++qn]=i;
        for(i=1;i<=qn;++i)
        {
            fj[q[i]]=0;
            for(j=h[q[i]];j;j=e[j].nx)
            {
                if(d[q[i]]+e[j].w==d[e[j].t])fj[q[i]]+=fj[e[j].t]*e[j].c;
                if(d[e[j].t]+e[j].w==d[q[i]]&&!--r[e[j].t])q[++qn]=e[j].t;
            }
            if(q[i]!=s)ans[q[i]]+=a[s]*fk[q[i]]*fj[q[i]];
            fj[q[i]]+=a[q[i]]/fk[q[i]];
        }
    }
    int main()
    {
        int m,i,j,x,y,w;double c;
        scanf("%d%d",&n,&m);
        for(i=1;i<=n;++i)scanf("%d",&a[i]);
        while(m--)scanf("%d%d%d%lf",&x,&y,&w,&c),ins(x,y,w,c);
        for(i=1;i<=n;++i)dj(i),pre(),solve(i);
        for(i=1;i<=n;++i)printf("%.7lf
    ",(double)ans[i]);
    }

    D.[Ctsc2015]gender

    思路:拿hzwer的标程研究了下,貌似题目有个很重要的东西没说,就是每条链的第一只一定同辈(至少hzwer的标程里貌似是这么认为的)……于是我们先用并查集搞出每只羊的辈分,每一辈之间的繁衍关系相互独立,$left lfloor 10ln(1+A) ight floor$这个式子太玄学,显然我们只能枚举A(事实上只要枚举$left lfloor 10ln(1+A) ight floor$),枚举确定了这个式子的值后,由于K很小而且每一辈独立,我们可以用最小割求出每一辈链上的点的各个改造情况下的最大收益(最基本的文理分科,不会请绕道),然后状压DP,f[i][j][k]表示前i辈,j个相邻的不同,最后一辈链上的点的改造情况为k,最后用满足$left lfloor 10ln(1+j) ight floor$等于我们枚举出的值的f[n][j][k]来更新答案,复杂度O(很复杂)。

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0';
        return x; 
    }
    #define MN 1000
    #define MM 10000
    #define MV 21000
    #define ME 61000
    #define S MV+1
    #define T MV+2
    #define INF 0x7FFFFFFF
    char s[MN+5];
    int n,k,m,p,c[MN+5],l[MN+5],d[MN+5],f[MN+5],xx[MM+5],yy[MM+5],w1[MM+5],w2[MM+5],A[205];
    int qv[205][MN+5],qe[205][MM+5];
    ll ans,G[55][16],F[55][205][16];
    int gf(int k){return f[k]?f[k]=gf(f[k]):k;}
    namespace MaxFlow
    {
        struct edge{int nx,t,w;}e[ME*2+5];
        int h[MV+5],en=1,d[MV+5],q[MV+5],qn,c[MV+5];
        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 k,u=0;
            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,min(e[i].w,r-u));
                u+=k;e[i].w-=k;e[i^1].w+=k;
                if(u==r)return u;
            }
            return d[x]=0,u;
        }
        ll dinic(){ll res=0;while(bfs())res+=dfs(S,INF);return res;}
    };
    void cal(int ln,int x,int y)
    {
        ll res=0;int i,p,cnt=m;
        using MaxFlow::ins;
        for(i=1;i<=qv[x][0];++i)
        {
            p=qv[x][i];
            if(l[p])if(y&(1<<l[p]-1))ins(S,p,INF),res-=c[p];else ins(p,T,INF);
            else ins(p,T,c[p]);
        }
        for(i=1;i<=qe[x][0];++i)
        {
            p=qe[x][i];
            res+=ln*(w1[p]+w2[p]);
            ins(S,++cnt,ln*w2[p]);
            ins(cnt,xx[p],INF);ins(cnt,yy[p],INF);
            ins(++cnt,T,ln*w1[p]);
            ins(xx[p],cnt,INF);ins(yy[p],cnt,INF);
        }
        G[x][y]=res-MaxFlow::dinic();
        using MaxFlow::h;
        for(i=1;i<=qv[x][0];++i)h[qv[x][i]]=0;
        for(i=m;++i<=cnt;)h[i]=0;
        h[S]=h[T]=0;MaxFlow::en=1;
    }
    void dp(int ln)
    {
        int i,j,l,p,d,df;
        memset(F,128,sizeof(F));
        for(l=0;l<1<<k;++l)F[1][0][l]=G[1][l];
        for(i=1;i<n;++i)for(j=0;A[j]<=ln;++j)for(l=0;l<1<<k;++l)
            if(F[i][j][l]>F[0][0][0])for(p=0;p<1<<k;++p)
            {
                for(d=df=0;d<k;++d)if((l&(1<<d))!=(p&(1<<d)))++df;
                if(A[j+df]<=ln)
                    F[i+1][j+df][p]=max(F[i+1][j+df][p],F[i][j][l]+G[i+1][p]);
            }
        for(j=0;A[j]<=ln;++j)if(A[j]==ln)for(l=0;l<1<<k;++l)ans=max(ans,F[n][j][l]);
    }
    int main()
    {
        int i,j,x;double wd;
        n=read();k=read();m=read();p=read();
        scanf("%s",s+1);
        for(i=1;i<=m;++i)c[i]=read();
        for(i=1;i<=k;++i)for(j=1;j<=n;++j)l[x=read()]=i,d[x]=j;
        for(i=1;i<=p;++i)
            xx[i]=read(),yy[i]=read(),w1[i]=read(),
            scanf("%lf",&wd),w2[i]=int(w1[i]*wd),
            gf(xx[i])!=gf(yy[i])?f[gf(xx[i])]=gf(yy[i]):0;
        for(i=1;i<=m;++i)if(d[i])d[gf(i)]=d[i];
        for(i=1;i<=m;++i)d[i]=d[gf(i)]?d[gf(i)]:1,qv[d[i]][++qv[d[i]][0]]=i;
        for(i=1;i<=p;++i)qe[d[xx[i]]][++qe[d[xx[i]]][0]]=i;
        for(i=0;i<=(n-1)*k;++i)A[i]=int(10*log(i+1));A[i]=INF;
        for(i=0;i<=(n-1)*k;++i)if(!i||A[i]!=A[i-1])
        {
            for(j=1;j<=n;++j)for(x=0;x<1<<k;++x)cal(A[i],j,x);
            dp(A[i]);
        }
        printf("%lld",ans);
    }
  • 相关阅读:
    学习进度条40
    学习进度条39
    学习进度条38
    学习进度条37
    学习进度条36
    iReport5.6.0使用说明
    Mysql 如何创建一张临时表
    SQL语句出现sql关键字
    SQL-order by两个字段同时排序
    js中==和===区别
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170407C.html
Copyright © 2020-2023  润新知