zoukankan      html  css  js  c++  java
  • 2017-4-14校内训练

    hzwer拿了几道noi中比较简单的给我们做

    A.[NOI2009]植物大战僵尸

    思路:考虑最小割,如果一个植物的权值x是正的,我们先默认吃掉它,使答案加上x并让S向这个点连x,割这条边相当于不吃这个植物,否则让这个点向T连-x,割这条边相当于吃这个植物,每个植物让它能攻击到的格子和它的前一格向它连INF,表示要么不吃它能保护到的,要么吃它,如果构成了环,这些植物必然都不能被吃,判完环后环上的点全部向T连INF即可。

    #include<cstdio>
    #include<cstring>
    inline int read()
    {
        int x,f=1;char c;
        while((c=getchar())<'0'||c>'9')if(c=='-')f=0;
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return f?x:-x;
    }
    #define MV 600
    #define ME 400000
    #define S MV+1
    #define T MV+2
    #define INF 0x7FFFFFFF
    #define p(x,y) ((x)*30+(y)+1)
    struct edge{int nx,t,w;}e[ME*2+5];
    int h[MV+5],en=1,d[MV+5],c[MV+5],q[MV+5],qn,df[MV+5],lw[MV+5],cnt,inq[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,r-u<e[i].w?r-u:e[i].w);
            e[i].w-=k;e[i^1].w+=k;u+=k;
            if(u==r)return r;
        }
        return d[x]=0,u;
    }
    void dfs(int x)
    {
        int i,u;
        df[x]=lw[x]=++cnt;inq[q[qn++]=x]=1;
        for(int i=h[x];i;i=e[i].nx)if(e[i].w)
        {
            if(!df[e[i].t])dfs(e[i].t);
            if(inq[e[i].t]&&lw[e[i].t]<lw[x])lw[x]=lw[e[i].t];
        }
        u=q[qn-1]!=x;
        if(df[x]==lw[x])for(;q[qn]!=x;u?(ins(q[qn],T,INF),0):0)inq[q[--qn]]=0;
    }
    int main()
    {
        int n,m,i,j,k,x,ans=0;
        n=read();m=read();
        for(i=0;i<n;++i)for(j=0;j<m;++j)
        {
            x=read();
            if(x>0)ans+=x,ins(S,p(i,j),x);
            else ins(p(i,j),T,-x);
            if(j)ins(p(i,j-1),p(i,j),INF);
            for(k=read();k--;)x=read(),ins(p(x,read()),p(i,j),INF);
        }
        for(i=0;i<n;++i)for(j=0;j<m;++j)if(!df[p(i,j)])dfs(p(i,j));
        while(bfs())ans-=dfs(S,INF);
        printf("%d",ans);
    }

    B.[Noi2011]阿狸的打字机

    之前做过了,题解戳这里

    C.[NOI2005]瑰丽华尔兹

    思路:用f[i][j][k]表示前i段时间过后,钢琴在(j,k)的最长路程,转移很显然单调队列嘛,复杂度O(nmk)。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    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*10+c-'0';
        return x;
    }
    #define MN 200
    int f[MN+5][MN+5][MN+5],q[MN+5],ql,qr;
    char s[MN+5][MN+5];
    int main()
    {
        int n,m,x,y,t,i,j,xx,yy,ans=0;
        n=read();m=read();
        memset(f,200,sizeof(f));
        x=read();f[0][x][read()]=0;t=read();
        for(i=1;i<=n;++i)scanf("%s",s[i]+1);
        for(i=1;i<=t;++i)
        {
            x=read();x=read()-x+1;y=read();
            if(y==1)for(yy=1;yy<=m;++yy)for(ql=1,qr=0,xx=n;xx;--xx)
            {
                while(ql<=qr&&f[i-1][xx][yy]+xx>=f[i-1][q[qr]][yy]+q[qr])--qr;q[++qr]=xx;
                while(q[ql]-xx>x)++ql;
                if(s[xx][yy]=='.')f[i][xx][yy]=f[i-1][q[ql]][yy]+q[ql]-xx;
                else ql=1,qr=0;
            }
            if(y==2)for(yy=1;yy<=m;++yy)for(ql=1,qr=0,xx=1;xx<=n;++xx)
            {
                while(ql<=qr&&f[i-1][xx][yy]-xx>=f[i-1][q[qr]][yy]-q[qr])--qr;q[++qr]=xx;
                while(xx-q[ql]>x)++ql;
                if(s[xx][yy]=='.')f[i][xx][yy]=f[i-1][q[ql]][yy]+xx-q[ql];
                else ql=1,qr=0;
            }
            if(y==3)for(xx=1;xx<=n;++xx)for(ql=1,qr=0,yy=m;yy;--yy)
            {
                while(ql<=qr&&f[i-1][xx][yy]+yy>=f[i-1][xx][q[qr]]+q[qr])--qr;q[++qr]=yy;
                while(q[ql]-yy>x)++ql;
                if(s[xx][yy]=='.')f[i][xx][yy]=f[i-1][xx][q[ql]]+q[ql]-yy;
                else ql=1,qr=0;
            }
            if(y==4)for(xx=1;xx<=n;++xx)for(ql=1,qr=0,yy=1;yy<=m;++yy)
            {
                while(ql<=qr&&f[i-1][xx][yy]-yy>=f[i-1][xx][q[qr]]-q[qr])--qr;q[++qr]=yy;
                while(yy-q[ql]>x)++ql;
                if(s[xx][yy]=='.')f[i][xx][yy]=f[i-1][xx][q[ql]]+yy-q[ql];
                else ql=1,qr=0;
            }
        }
        for(i=1;i<=n;++i)for(j=1;j<=m;++j)ans=max(ans,f[t][i][j]);
        printf("%d",ans);
    }

    D.[Noi2014]动物园

    思路:首先kmp弄出next数组,num[i]就是每次令i=next[i],在变成0前有多少次不超过i/2,先不考虑不超过i/2的限制,则num[i]=num[next[i]]+1,对于每个next[i]>i/2,扣掉它next几次后会小等于i/2,由于它的循环节是i-next[i],每次取next都会使它的值减小i-next[i],除一下就好了,复杂度O(n)。

    #include<cstdio>
    #include<cstring>
    #define MN 1000000
    #define MOD 1000000007
    char s[MN+5];
    int nx[MN+5],f[MN+5];
    int main()
    {
        int n,i,j,ans;
        scanf("%d",&n);
        while(n--)
        {
            scanf("%s",s+1);
            for(f[1]=1,i=2,j=0;s[i];++i)
            {
                while(j&&s[i]!=s[j+1])j=nx[j];
                if(s[i]==s[j+1])++j;
                f[i]=f[nx[i]=j]+1;
            }
            for(ans=i=1;s[i];++i)
            {
                if(nx[i]*2>i)f[i]-=(nx[i]-i/2+i-nx[i]-1)/(i-nx[i]);
                ans=1LL*ans*f[i]%MOD;
            }
            printf("%d
    ",ans);
        }
    }
  • 相关阅读:
    和Mac有关的所有快捷键整理
    Python学习笔记
    在PHP的AWS SDK 的上传功能中指定Content-Type
    Docker 部署 Yapi
    PHP 队列
    数据库设计之一 数据库范式
    docker centos PHP7.2 安装 bcmath数学扩展
    记联调微信支付,调起微信支付之后显示支付验证失败
    记Windows 2012 FTP配置之后 客户端登陆报错
    记一次 MAC 安装 homebrew 报错解决
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170414C.html
Copyright © 2011-2022 走看看