11.2

T1 下棋

Sol
直接记搜就可以了,记\(f[i][j][k][l]\)表示当前放了\(i\)个白棋\(j\)个黑棋,直至目前白棋\(-\)黑棋最大值为\(k\),黑棋\(-\)白棋最大值为\(l\)
能放黑棋白棋就枚举放置即可。
Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=160,maxk=23,p=1000000007;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[20],len;
        len=0;
        if(x<0)putchar('-'),x=-x;
        if(x==0)
        {
            putchar('0');return;
        }
        while(x)
        {
            s[++len]=x%10;
            x/=10;
        }
        for(int i=len;i;i--)putchar(s[i]+'0');
        return;
    }
}
using namespace io;
int f[maxn][maxn][maxk][maxk];
int n,m,k;
inline int dfs(int x,int y,int mxx,int mxy)
{
    if(~f[x][y][mxx][mxy])return f[x][y][mxx][mxy];
    int &ans=f[x][y][mxx][mxy];
    ans=0;
    if(x==n&&y==m)return ans=1;
    if(x<n&&mxx<k)ans+=dfs(x+1,y,mxx+1,max(0,mxy-1));
    if(y<m&&mxy<k)ans+=dfs(x,y+1,max(0,mxx-1),mxy+1);
    if(ans>=p)ans-=p;
    return ans;
}
int main()
{
    freopen("chess.in","r",stdin);
    freopen("chess.out","w",stdout);
    n=read();m=read();k=read();
    memset(f,-1,sizeof(f));
    dfs(0,0,0,0);
    print(f[0][0][0][0]);
    return 0;
}

T2 出租车

Sol
考场上多了一维还写的直接DP,还带数据分治。这导致我对于我那8kb代码无能为力……
考虑\(dp[i][now][gpa][gpb][gpc][gpd]\)表示当前第\(i\)个人要上车,现在车在\(now\),目前车上四个人的目的地。
发现车子满载的时候根本没法上人,所以可以省去一维。那么转移方程就是先看能不能把一个人送下车,然后判断是否全部人下车且无人要上车,然后如果车上已经三个人了就枚举载上第四个人以后谁先下车,最后是再拉一个人上车。
细节还好,不算很多,且代码复制粘贴地方多,看着挺整齐。
Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=2010,maxk=11;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[20],len;
        len=0;
        if(x<0)putchar('-'),x=-x;
        if(x==0)
        {
            putchar('0');return;
        }
        while(x)
        {
            s[++len]=x%10;
            x/=10;
        }
        for(int i=len;i;i--)putchar(s[i]+'0');
        return;
    }
}
using namespace io;
int n,k;
int u[maxn],v[maxn];
int f[maxn][maxk][maxk][maxk][maxk];
inline int dfs(int i,int now,int gpa,int gpb,int gpc)
{
    if(~f[i][now][gpa][gpb][gpc])return f[i][now][gpa][gpb][gpc];
    int &rst=f[i][now][gpa][gpb][gpc];rst=1000000000;
    if(gpa)rst=min(rst,dfs(i,gpa,0,gpb,gpc)+abs(now-gpa)+1);
    if(gpb)rst=min(rst,dfs(i,gpb,gpa,0,gpc)+abs(now-gpb)+1);
    if(gpc)rst=min(rst,dfs(i,gpc,gpa,gpb,0)+abs(now-gpc)+1);
    if(i==n+1)
    {
        if(gpa==0&&gpb==0&&gpc==0)return rst=0;
        return rst;
    }
    if(gpa&&gpb&&gpc)
    {
        rst=min(rst,dfs(i+1,gpa,v[i],gpb,gpc)+abs(now-u[i])+abs(u[i]-gpa)+2);
        rst=min(rst,dfs(i+1,gpb,gpa,v[i],gpc)+abs(now-u[i])+abs(u[i]-gpb)+2);
        rst=min(rst,dfs(i+1,gpc,gpa,gpb,v[i])+abs(now-u[i])+abs(u[i]-gpc)+2);
        rst=min(rst,dfs(i+1,v[i],gpa,gpb,gpc)+abs(now-u[i])+abs(u[i]-v[i])+2);
    }else
    {
        if(!gpa)rst=min(rst,dfs(i+1,u[i],v[i],gpb,gpc)+abs(now-u[i])+1);
        if(!gpb)rst=min(rst,dfs(i+1,u[i],gpa,v[i],gpc)+abs(now-u[i])+1);
        if(!gpc)rst=min(rst,dfs(i+1,u[i],gpa,gpb,v[i])+abs(now-u[i])+1);
    }
    return rst;
}
int main()
{
    freopen("taxi.in","r",stdin);
    freopen("taxi.out","w",stdout);
    n=read();k=read();
    for(int i=1;i<=n;i++)u[i]=read(),v[i]=read();
    memset(f,-1,sizeof(f));
    printf("%d\n",dfs(1,1,0,0,0));
    return 0;
}

T3 堆石子

Sol
显然30分就是直接枚举每一堆选不选。
然后套个折半搜索就过了。。。我是傻逼。
Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=40;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[20],len;
        len=0;
        if(x<0)putchar('-'),x=-x;
        if(x==0)
        {
            putchar('0');return;
        }
        while(x)
        {
            s[++len]=x%10;
            x/=10;
        }
        for(int i=len;i;i--)putchar(s[i]+'0');
        return;
    }
}
using namespace io;
int n,s[maxn],m,ans=0;
int d1[1<<20],d2[1<<20];
int main()
{
    freopen("stone.in","r",stdin);
    freopen("stone.out","w",stdout);
    n=read();m=read();
    int half=n/2;
    for(int i=0;i<n;i++)s[i]=read()%m;
    for(int i=0;i<(1<<half);i++)
    {
        for(int j=0;j<half;j++)
        {
            if(i&(1<<j))
            {
                d1[i]+=s[j];if(d1[i]>=m)d1[i]-=m;
            }
        }
    }
    for(int i=0;i<(1<<n-half);i++)
    {
        for(int j=0;j<n-half;j++)
        {
            if(i&(1<<j))
            {
                d2[i]+=s[j+half];if(d2[i]>=m)d2[i]-=m;
            }
        }
    }
    sort(d1,d1+(1<<half));
    sort(d2,d2+(1<<n-half));
    int now=(1<<n-half)-1;
    for(int i=0;i<(1<<half);i++)
    {
        while(now>=0&&d1[i]+d2[now]>=m)now--;
        if(now>=0)ans=max(ans,d1[i]+d2[now]);
    }
    print(ans);putchar('\n');
    return 0;
}

T4 不稳定的导弹系统

Sol
考场降智以为是状压DP优化。。。
考虑先假设每个系统都能打到自己能打到的最大的点,然后在想如何调整使得保证合法且答案最大。假设每个格点之间连边变成机会成本,也就是替换成打这个目标会损失的答案。那么这样构造出一个图,要求出图的最小割就是最小调整代价。
但是有可能出现多行多列交叉,所以把每个点拆分成横点和竖点,横点向竖点连inf边,源点向南北向路径连inf边,东西向路径向汇点连inf边,点与点间连机会成本值边,剩下的网络流基操。

#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,maxm=100010,inf=1000000000;
namespace io
{
    inline int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=0;c=getchar();}
        while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c&15),c=getchar();
        return f?x:-x;
    }
    inline void print(int x)
    {
        static int s[20],len;
        len=0;
        if(x<0)putchar('-'),x=-x;
        if(x==0)
        {
            putchar('0');return;
        }
        while(x)
        {
            s[++len]=x%10;
            x/=10;
        }
        for(int i=len;i;i--)putchar(s[i]+'0');
        return;
    }
}
using namespace io;
struct edge
{
    int to,next,v;
}e[maxm];
int h[maxn],ei=1;
inline void add(int x,int y,int v)
{
    e[++ei]=(edge){y,h[x],v};
    h[x]=ei;
    e[++ei]=(edge){x,h[y],0};
    h[y]=ei;return;
}
int n,m,S,T,ans;
int p(int x,int y){return ((x-1)*m+y)*2;}
int q(int x,int y){return ((x-1)*m+y)*2-1;}
int a[60][60];
int dep[maxn];
queue<int>qu;
inline bool bfs()
{
    memset(dep,0,sizeof(dep));
    dep[S]=1;qu.push(S);
    while(!qu.empty())
    {
        int x=qu.front();qu.pop();
        for(int i=h[x];i;i=e[i].next)
        {
            int to=e[i].to;
            if(dep[to]||e[i].v==0)continue;
            dep[to]=dep[x]+1;
            qu.push(to);
        }
    }
    return dep[T]>0;
}
inline int dfs(int x,int maxflow)
{
    if(x==T)return maxflow;
    int flow=0;
    for(int i=h[x];i;i=e[i].next)
    {
        int to=e[i].to;
        if(dep[to]!=dep[x]+1||e[i].v==0)continue;
        int rst=dfs(to,min(maxflow-flow,e[i].v));
        if(rst==0)dep[to]=0;
        e[i].v-=rst;e[i^1].v+=rst;
        flow+=rst;
        if(flow==maxflow)break;
    }
    return flow;
}
inline void dinic()
{
    while(bfs())ans-=dfs(S,inf);
    return;
}
int main()
{
    freopen("missile.in","r",stdin);
    freopen("missile.out","w",stdout);
    n=read();m=read();S=n*m*2+1;T=S+1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            a[i][j]=read();
            add(p(i,j),q(i,j),inf);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            int mx=0;
            if(a[i][j]==-1)
            {
                add(S,p(i,j),inf);
                for(int k=1;k<=i;k++)mx=max(mx,a[k][j]);
                for(int k=2;k<=i;k++)
                {
                    add(p(k,j),p(k-1,j),mx-max(a[k][j],0));
                }
            }
            if(a[i][j]==-2)
            {
                add(S,p(i,j),inf);
                for(int k=i;k<=n;k++)mx=max(mx,a[k][j]);
                for(int k=i;k<n;k++)
                {
                    add(p(k,j),p(k+1,j),mx-max(a[k][j],0));
                }
            }
            if(a[i][j]==-3)
            {
                add(q(i,j),T,inf);
                for(int k=1;k<=j;k++)mx=max(mx,a[i][k]);
                for(int k=2;k<=j;k++)
                {
                    add(q(i,k-1),q(i,k),mx-max(a[i][k],0));
                }
            }
            if(a[i][j]==-4)
            {
                add(q(i,j),T,inf);
                for(int k=j;k<=m;k++)mx=max(mx,a[i][k]);
                for(int k=j;k<m;k++)
                {
                    add(q(i,k+1),q(i,k),mx-max(a[i][k],0));
                }
            }
            ans+=mx;
        }
    }
    dinic();
    print(ans);putchar('\n');
    return 0;
}
posted @ 2021-11-02 20:35  wwlvv  阅读(103)  评论(0)    收藏  举报