2017/8/9 离线赛

来源:互联网 发布:北京软件开发平均工资 编辑:程序博客网 时间:2024/05/22 03:26

T1 01完美矩阵

    这题考试的时候枚举完两行,找出全1的列,就懵逼了。没有继续往下想,真是可惜了,实际上蛮容易的。枚举上下两行,然后扫每一列,遇到一条全是1的列就塞进数组,遇到上下两行有0的列就求答案,再清空,这显然是正确的。因为能组成矩形的两列之间一定是连续的1。求答案的时候,只要存一个前缀和的cnt数组就行了,假设求到当前列的前缀和为sum,那么这列能形成的矩形数就是cnt[sum1]+cnt[sum]+cnt[sum1],因为之前前缀和是这三种的列都能与当前列组成满足条件的矩形。

int s[M],cnt;int n,m,ans;bool mark[M][M];int sum[M][M];int num[M*M];int u[]={-1,1};void work(int a,int b){    num[0]++;    int tmp=0;    for(int i=2;i<=cnt;++i){        //(a+1,s[i-1]+1),(b-1,s[i]-1)        int t=sum[b-1][s[i]-1]-sum[a][s[i]-1]-sum[b-1][s[i-1]]+sum[a][s[i-1]];        ans+=num[tmp+t-1]+num[tmp+t]+num[tmp+t+1];        tmp+=t;//中间的块        tmp+=b-a-1;//当前列        num[tmp]++;    }    num[0]--;    tmp=0;    for(int i=2;i<=cnt;++i){        int t=sum[b-1][s[i]-1]-sum[a][s[i]-1]-sum[b-1][s[i-1]]+sum[a][s[i-1]];        tmp+=t;        tmp+=b-a-1;        num[tmp]--;    }}int main(){    Rd(n);Rd(m);    for(int i=1;i<=n;++i)    for(int j=1;j<=m;++j){        Rd(mark[i][j]);        sum[i][j]=sum[i-1][j-1]+sum[i][j-1]-sum[i-1][j-1]+sum[i-1][j]-sum[i-1][j-1]+u[mark[i][j]];    }    for(int i=1;i<=n;++i)    for(int j=i+1;j<=n;++j){        for(int k=1;k<=m;++k){            int t=sum[j][k]-sum[i-1][k]-sum[j][k-1]+sum[i-1][k-1];            if(t==j-i+1){                s[++cnt]=k;            }else if(!mark[i][k]||!mark[j][k]){                 work(i,j);                cnt=0;            }        }        if(cnt){            work(i,j);            cnt=0;        }    }    Pt(ans);    putchar('\n');    return 0;}

T2 codeforces 维修道路

    我可以知道,要选择的两条路径的端点一定是树的直径的端点。证明很简单:我们想要的是两条路径的长度的积最大,那就是要两条路径的长度尽可能长,长度尽可能平均,我们知道由树的直径的端点出发(这里指从直径两个端点出发),到其它节点的长度一定比由其它节点出发到达该点的长度长,假如选出的两条路径上不存在有点落在直径上,那它一定不是最优了,因为我们取一条路径的端点与直径端点相连的路径一定比这条路径更长。我们只要把直径抽离出来,求出直径上每个点能拉出来的最长的链,然后求一遍前缀和后缀最大值,最后枚举一个点为分界线即可。

struct edge{    int v,nxt;}e[M<<1];int n;int head[M],edgecnt;int fa[M];void add_edge(int u,int v){    e[++edgecnt].v=v;e[edgecnt].nxt=head[u];head[u]=edgecnt;}int s,id;bool mark[M];void dfs(int x,int t,int d){    fa[x]=t;    if(d>s){id=x;s=d;}    for(int i=head[x];~i;i=e[i].nxt)    if(e[i].v!=t)dfs(e[i].v,x,d+1);}void solve(int x,int d){    mark[x]=1;    if(s<d)s=d;    for(int i=head[x];~i;i=e[i].nxt)    if(!mark[e[i].v])solve(e[i].v,d+1);}int d[M],cnt;int A[M],mxL[M],mxR[M];int main(){    int a,b;    memset(head,-1,sizeof(head));    Rd(n);    for(int i=1;i<n;i++){        Rd(a);Rd(b);        add_edge(a,b);        add_edge(b,a);    }    dfs(1,-1,0);    s=0;    memset(fa,-1,sizeof(fa));    dfs(id,-1,0);    for(int i=id;~i;i=fa[i])d[++cnt]=i;    for(int i=1;i<=cnt;i++){        int x=d[i];        mark[x]=1;        for(int j=head[x];~j;j=e[j].nxt){            int v=e[j].v;            if(mark[v]||v==fa[x])continue;            s=0;            solve(v,1);            if(A[i]<s)A[i]=s;        }    }    for(int i=1;i<=cnt;i++)    mxL[i]=max(i-1+A[i],mxL[i-1]);    for(int i=cnt;i>=1;i--)    mxR[i]=max(cnt-i+A[i],mxR[i+1]);    ll ans=0;    for(int i=1;i<cnt;i++)    ans=max(ans,1LL*mxL[i]*mxR[i+1]);    Pt(ans);    putchar('\n');    return 0;}

T3 计蒜客 颜值选择

    考试的时候我就敲了个O(mk4)的dp水了50分,就是暴力枚举前一列的数字和后一列的数字。 假如是两行就要一次枚举四个数字,显然会超时,那么如何能少枚举一个数字呢?我们定义dp[i][x][y]表示第i列上面的数字为x,下面的数字为y时的最优解,假设上一列的状态是dp[i1][a][b],那么转移方程就是:

dp[i][x][y]=Min(dp[i1][a][b]+|a+x|+|b+y|)+|x+y|+cost1,i,x+cost2,i,y
其中,costi,j,x表示第i行第j列为x时的成本。

    对于这条转移方程,我们如果枚举了xya,那么我们就只要求出Min(dp[i1][a][b]+|b+y|)即可,因为其它量在枚举过后都是已知的了。但是要求的量里存在绝对值,我们要把绝对值展开:当b+y0yb时,值为Min(dp[i1][a][b]+b+y),这种情况对答案的贡献是个前缀;当b+y0(把等于0的情况加上好写一点)即yb时,值为Min(dp[i1][a][b]by),这种情况对答案的贡献是个后缀。因此我们只要在转移之前处理出上一列的前后缀数组即可,就是说我们在最外层枚举xa,再枚举b求出前后缀数组(前缀L[b]=dp[i1][a][b]+b,后缀R[b]=dp[i1][a][b]b),最后枚举y即可。

dp[i][x][y]=min(L[y]+y,R[y]y)+|a+x|+|x+y|+cost1,i,x+cost2,i,y

struct P2{    int ans,P;    int cost[3][31][61];    int dp[2][61][61];    int L[61],R[61];    void solve(){        for(int i=1;i<=2;i++)        for(int j=1;j<=m;j++)        for(int x=-k;x<=k;x++)        cost[i][j][x+P]=(abs(x+i+j)^U[i][j])*W[i][j];        bool cur=0;        for(int i=-k;i<=k;i++)        for(int j=-k;j<=k;j++)        dp[cur][i+P][j+P]=cost[1][1][i+P]+cost[2][1][j+P]+abs(i+j);        for(int i=2;i<=m;i++){            cur=!cur;            memset(dp[cur],-1,sizeof(dp[cur]));            for(int x=-k;x<=k;x++)            for(int a=-k;a<=k;a++){                for(int b=-k;b<=k;b++){                    L[-b+P]=dp[!cur][a+P][b+P]+b;                    R[-b+P]=dp[!cur][a+P][b+P]-b;                }                for(int b=-k+1;b<=k;b++)L[b+P]=min(L[b+P],L[b-1+P]);                for(int b=k-1;b>=-k;b--)R[b+P]=min(R[b+P],R[b+1+P]);                for(int y=-k;y<=k;y++)                check(dp[cur][x+P][y+P],min(L[y+P]+y,R[y+P]-y)+abs(a+x)+abs(x+y)+cost[1][i][x+P]+cost[2][i][y+P]);            }        }        for(int i=-k;i<=k;i++)        for(int j=-k;j<=k;j++)        if(~dp[cur][i+P][j+P])        check(ans,dp[cur][i+P][j+P]);        Pt(ans);        putchar('\n');    }    P2(){ans=-1;P=30;memset(dp,-1,sizeof(dp));}}P2;

    满分的解法太烦,请看题解。

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<algorithm>#include<iostream>#define For(i,a,b) for(int i=a;i<=b;++i)#define Ror(i,a,b) for(int i=b;i>=a;--i)#define M 888888#define oo 2000000000using namespace std;template <class T>inline void Rd(T &res){    char c;res=0;int k=1;    while(c=getchar(),c<48&&c!='-');    if(c=='-'){k=-1;c='0';}    do{        res=(res<<3)+(res<<1)+(c^48);    }while(c=getchar(),c>=48);    res*=k;}template <class T>inline void Pt(T res){    if(res<0){        putchar('-');        res=-res;    }    if(res>=10)Pt(res/10);    putchar(res%10+48);}void check(int &a,int b){    if(a==-1||a>b)a=b;}int n,m,k;int U[20][35],W[20][35];struct P1{    int ans,P;    int cost[31][61];    int dp[2][61];    void solve(){        for(int i=1;i<=m;i++)        for(int j=-k;j<=k;j++)        cost[i][j+P]=(abs(j+1+i)^U[1][i])*W[1][i];        bool cur=0;        for(int i=-k;i<=k;i++)        dp[cur][i+P]=cost[1][i+P];        for(int i=2;i<=m;i++){            cur=!cur;            memset(dp[cur],-1,sizeof(dp[cur]));            for(int j=-k;j<=k;j++)            if(~dp[!cur][j+P]){                for(int x=-k;x<=k;x++)                check(dp[cur][x+P],dp[!cur][j+P]+abs(j+x)+cost[i][x+P]);            }        }        for(int i=-k;i<=k;i++)        if(~dp[cur][i+P])check(ans,dp[cur][i+P]);        Pt(ans);        putchar('\n');    }    P1(){ans=-1,P=30;memset(dp,-1,sizeof(dp));}}P1;struct P2{    int ans,P;    int cost[3][31][61];    int dp[2][61][61];    int L[61],R[61];    void solve(){        for(int i=1;i<=2;i++)        for(int j=1;j<=m;j++)        for(int x=-k;x<=k;x++)        cost[i][j][x+P]=(abs(x+i+j)^U[i][j])*W[i][j];        bool cur=0;        for(int i=-k;i<=k;i++)        for(int j=-k;j<=k;j++)        dp[cur][i+P][j+P]=cost[1][1][i+P]+cost[2][1][j+P]+abs(i+j);        for(int i=2;i<=m;i++){            cur=!cur;            memset(dp[cur],-1,sizeof(dp[cur]));            for(int x=-k;x<=k;x++)            for(int a=-k;a<=k;a++){                for(int b=-k;b<=k;b++){                    L[-b+P]=dp[!cur][a+P][b+P]+b;                    R[-b+P]=dp[!cur][a+P][b+P]-b;                }                for(int b=-k+1;b<=k;b++)L[b+P]=min(L[b+P],L[b-1+P]);                for(int b=k-1;b>=-k;b--)R[b+P]=min(R[b+P],R[b+1+P]);                for(int y=-k;y<=k;y++)                check(dp[cur][x+P][y+P],min(L[y+P]+y,R[y+P]-y)+abs(a+x)+abs(x+y)+cost[1][i][x+P]+cost[2][i][y+P]);            }        }        for(int i=-k;i<=k;i++)        for(int j=-k;j<=k;j++)        if(~dp[cur][i+P][j+P])        check(ans,dp[cur][i+P][j+P]);        Pt(ans);        putchar('\n');    }    P2(){ans=-1;P=30;memset(dp,-1,sizeof(dp));}}P2;struct P3{    int S,T,P,tot;    int h[M],head[M],edgecnt;    int id[20][35][65];    int dep[M],Q[M];    struct edge{        int v,nxt,f;    }e[M<<1];    int calc(int x,int y,int z){        return (abs(x+y+z)^U[x][y])*W[x][y];    }    void Add(int a,int b,int c){        e[edgecnt]=(edge){b,head[a],c};head[a]=edgecnt++;        e[edgecnt]=(edge){a,head[b],0};head[b]=edgecnt++;    }    void build(){        memset(head,-1,sizeof(head));        edgecnt=0;        S=1,T=2,tot=2;        For(i,1,n)For(j,1,m){            int p=(i+j)&1;            if(p){                For(t,-k,k)id[i][j][t+k+1]=++tot;                Add(S,id[i][j][1],(abs(-k+i+j)^U[i][j])*W[i][j]);                for(int t=-k+1;t<k;t++)                    Add(id[i][j][t+k],id[i][j][t+k+1],(abs(t+i+j)^U[i][j])*W[i][j]);                Add(id[i][j][k+k],T,(abs(k+i+j)^U[i][j])*W[i][j]);            }else{                Ror(t,-k,k)id[i][j][k-t+1]=++tot;                Add(S,id[i][j][1],(abs(k+i+j)^U[i][j])*W[i][j]);                for(int t=k-1;t>-k;t--)                    Add(id[i][j][k-t],id[i][j][k-t+1],(abs(t+i+j)^U[i][j])*W[i][j]);                Add(id[i][j][k+k],T,(abs(-k+i+j)^U[i][j])*W[i][j]);            }            For(t,1,2*k){                if(i>1){                    Add(id[i-1][j][t],id[i][j][t],1);                    Add(id[i][j][t],id[i-1][j][t],1);                }                if(j>1){                    Add(id[i][j-1][t],id[i][j][t],1);                    Add(id[i][j][t],id[i][j-1][t],1);                }            }        }    }    bool BFS(){        memset(dep,0,sizeof(dep));        int L=0,R=0;        dep[S]=1;        Q[R++]=S;        while(L<R){            int now=Q[L++];            for(int i=head[now];~i;i=e[i].nxt){                int v=e[i].v;                if(e[i].f&&!dep[v]){                    dep[v]=dep[now]+1;                    Q[R++]=v;                }            }        }        return dep[T];    }    int dfs(int x,int t,int f){        if(x==t)return f;        for(int &i=h[x];~i;i=e[i].nxt){            int v=e[i].v;            if(dep[v]==dep[x]+1&&e[i].f){                int d=dfs(v,t,min(e[i].f,f));                if(d){                    e[i].f-=d;                    e[i^1].f+=d;                    return d;                }            }        }        return 0;    }    int Dinic(){        int ans=0,f;        while(BFS()){            for(int i=0;i<=tot;i++)h[i]=head[i];            while(f=dfs(S,T,2e9))ans+=f;        }        return ans;    }    void solve(){        build();//      for(int i=0;i<=0;i++)//      for(int j=head[i];~j;j=e[j].nxt){//          cout<<i<<" "<<e[j].v<<" "<<e[j].f<<endl;//      }        Pt(Dinic());        putchar('\n');    }    P3(){P=30;}}P3;int main(){    int size = 32 << 20; // 32MB    char *p = (char*)malloc(size) + size;    __asm__("movl %0, %%esp\n" :: "r"(p));    Rd(n);Rd(m);Rd(k);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    Rd(U[i][j]);    for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)    Rd(W[i][j]);//  if(n==1)P1.solve();//  else if(n==2)P2.solve();    P3.solve();    return 0;}
原创粉丝点击