loj3500.「联合省选 2021 A」矩阵游戏

题目链接

值域的限制看起来非常强,很不好弄。

想到 ckw 的一句话:碰到一个题,先想一想如果没有某些操作该怎么做。比如,一个数据结构题如果没有询问怎么做?

于是扔了值域的限制,遂发现变成了个傻逼题,钦定第一行第一列为 \(0\) 然后大力推一遍就好了。

现在再回来考虑值域。有一个显然的调整是每行或每列的每个数依次 \(+c/-c\)\(c\) 是常数)。假设作用在第 \(i\) 行的 \(c\) 大小为 \(c_i\),列的为 \(d_i\),那么 \(\forall 1\leq i\leq n,1\leq j\leq m\)\(0\leq a_{i,j}\pm c_i\pm d_j\leq10^6\),移项得到 \(-a_{i,j}\leq\pm c_i\pm d_j\leq10^6-a_{i,j}\)

这玩意又有加又有减的还是没法处理,但我们发现符号的正负是有规律的,\(c,d\) 都是奇正偶负。那么我们把偶数行的 \(c\) 取反,奇数列的 \(d\) 取反,所有的限制都变成了 \(-a_{i,j}\leq\pm(c_i-d_j)\leq10^6-a_{i,j}\),这个就是经典的差分约束了。

写出来之后发现只有 50,原来是恶毒出题人卡常数,加了个 SLF-swap 就过了。

#include<iostream>
#include<cstdio>
#include<deque>
#include<cstring>
using namespace std;
struct edge
{
    int nxt,to,weight;
}e[301*301*8];
int t,n,m,s,tot,h[301<<1];
long long a[301][301],b[301][301],dis[301<<1];
int cnt[301<<1];
bool vis[301<<1];
inline int read()
{
    int x=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return x;
}
void print(long long x)
{
    if(x>=10)
        print(x/10);
    putchar(x%10+'0');
}
inline void add(int x,int y,int w)
{
    e[++tot].nxt=h[x];
    h[x]=tot;
    e[tot].to=y;
    e[tot].weight=w;
}
inline bool SPFA()
{
    deque<int> q;
    for(register int i=1;i<=s;++i)
    {
        dis[i]=1ll<<60;
        cnt[i]=vis[i]=0;
    }
    q.push_back(s);
    dis[s]=0;
    while(!q.empty())
    {
        int k=q.front();
        q.pop_front();
        vis[k]=0;
        if(++cnt[k]>=n+m)
            return 0;
        for(register int i=h[k];i;i=e[i].nxt)
            if(dis[e[i].to]>dis[k]+e[i].weight)
            {
                dis[e[i].to]=dis[k]+e[i].weight;
                if(!vis[e[i].to])
                {
                    vis[e[i].to]=1;
                    if(dis[q.front()]>dis[e[i].to])
                    {
                        q.push_back(q.front());
                        q.pop_front();
                        q.push_front(e[i].to);
                    }
                    else
                        q.push_back(e[i].to);
                }
            }
    }
    return 1;
}
signed main()
{
    t=read();
    while(t--)
    {
        n=read(),m=read();
        tot=0;
        memset(e,0,sizeof e);
        memset(h,0,sizeof h);
        for(register int i=1;i<n;++i)
            for(register int j=1;j<m;++j)
                b[i][j]=read();
        for(register int i=2;i<=n;++i)
            for(register int j=2;j<=m;++j)
            {
                a[i][j]=b[i-1][j-1];
                b[i][j-1]-=b[i-1][j-1];
                b[i-1][j]-=b[i-1][j-1];
                b[i][j]-=b[i-1][j-1];
            }
        s=n+m+1;
        for(register int i=1;i<=n;++i)
            add(s,i,0);
        for(register int i=1;i<=m;++i)
            add(s,i+n,0);
        for(register int i=1;i<=n;++i)
            for(register int j=1;j<=m;++j)
            {
                int minn=a[i][j],maxn=1e6-a[i][j];
                if((i+j)&1)
                {
                    add(i,j+n,maxn);
                    add(j+n,i,minn);
                }
                else
                {
                    add(j+n,i,maxn);
                    add(i,j+n,minn);
                }
            }
        if(!SPFA())
        {
            puts("NO");
            continue;
        }
        puts("YES");
        for(register int i=1;i<=n;++i,putchar('\n'))
            for(register int j=1;j<=m;++j,putchar(' '))
                if((i+j)&1)
                    print(a[i][j]+dis[j+n]-dis[i]);
                else
                    print(a[i][j]+dis[i]-dis[j+n]);
    }
    return 0;
}
posted @ 2021-08-15 20:36  绝顶我为峰  阅读(53)  评论(0编辑  收藏  举报