P7515 矩阵游戏

P7515 矩阵游戏 题解

链接P7515 [省选联考 2021 A 卷] 矩阵游戏

题意简述:给定\((n-1)\times(m-1)\)的矩阵\(b\),求是否存在一个\(n\times m\)的矩阵满足\(b_{i,j}=a_{i,j}+a_{i+1,j}+a_{i,j+1}+a_{i+1,j+1}\)\(\forall a_{i,j}\)为小于等于\(10^6\)次方的非负整数。

数据范围\(n,m\le 300,0\le a_{i,j}\le 10^6\)

Solution

发现很像线性规划问题。\(a_{i,j}\)有两个限制,\(b_{i,j}=a_{i,j}+a_{i+1,j}+a_{i,j+1}+a_{i+1,j+1}\)\(0\le a_{i,j}\le 10^6\)

观察性质,考虑差分约束。用条件1将条件2构造成\(a-b\le c\)\(a-b\ge c\)的形式。

显然构造三角不等式要让原矩阵支持加/减一个数,观察矩阵\(a\)的性质。

  • 性质1:对于矩阵\(a\)的每一行/每一列,让第一个元素\(+x\),第二个元素\(-x\),第三个元素\(+x\)\(b\)矩阵不会改变。

对于每个j经过的\(b_{i,j}\),有且仅有 2 个元素被经过,一加一减正好抵消。

设第\(i\)行加上了\(x_i\),第\(i\)列加上了\(y_i\)

所以,画出\(a\)矩阵的累加矩阵\(c\)

\[\begin{bmatrix} x_1+y_1&-x_1+y_2&x_1+y_3&-x_1+y_4&\cdots \\ x_2-y_1&-x_2-y_2&x_2-y_3&-x_2-y_4&\cdots \\ x_3+y_1&-x_3+y_2&x_3+y_3&-x_3+y_4&\cdots \\ x_4-y_1&-x_4-y_2&x_4-y_3&-x_4-y_4&\cdots \\ \vdots&\vdots&\vdots&\vdots&\ddots\\ \end{bmatrix} \]

所以\(0\le a_{i,j}+c_{i,j}\le10^6\),的\(-c_{i,j}\le a_{i,j}\le 10^6-c_{i,j}\)

我们得到了我们需要的不等式,但是由于一个问题,累加矩阵\(c\)不仅有\(a-b\)的形式,还有\(a+b\)的形式,前者是我们熟悉的差分约束,但后者我们还不会处理。

  • 性质2:对矩阵\(a\)进行黑白染色,记一个黑格为\(x-y\),白格为\(y-x\),发现对于每一行/每一列的颜色总为黑白交替的,由于黑白格的符号不相同,可直接染色。

本质上就是选出一些行和列,将\(x\)\(y\)的符号取反。

一起手玩一下:

先观察原矩阵中\(x\)的符号:

\[\begin{bmatrix} +&-&+&-&\cdots \\ +&-&+&-&\cdots \\ +&-&+&-&\cdots \\ +&-&+&-&\cdots \\ \vdots&\vdots&\vdots&\vdots&\ddots\\ \end{bmatrix} \]

第一、三行不变,改变第二、四行。

\[\begin{bmatrix} x_1+y_1&-x_1+y_2&x_1+y_3&-x_1+y_4&\cdots \\ -x_2-y_1&x_2-y_2&-x_2-y_3&x_2-y_4&\cdots \\ x_3+y_1&-x_3+y_2&x_3+y_3&-x_3+y_4&\cdots \\ -x_4-y_1&x_4-y_2&-x_4-y_3&x_4-y_4&\cdots \\ \vdots&\vdots&\vdots&\vdots&\ddots\\ \end{bmatrix} \]

只观察\(x\)的符号:

\[\begin{bmatrix} +&-&+&-&\cdots \\ -&+&-&+&\cdots \\ +&-&+&-&\cdots \\ -&+&-&+&\cdots \\ \vdots&\vdots&\vdots&\vdots&\ddots\\ \end{bmatrix} \]

同理,\(y\)也能染成这种正负交错的形式,一正一负正好是我们要的。

所以,操作完的矩阵为:

\[\begin{bmatrix} x_1-y_1&-x_1+y_2&x_1-y_3&-x_1+y_4&\cdots \\ -x_2+y_1&x_2-y_2&-x_2+y_3&x_2-y_4&\cdots \\ x_3-y_1&-x_3+y_2&x_3-y_3&-x_3+y_4&\cdots \\ -x_4+y_1&x_4-y_2&-x_4+y_3&x_4-y_4&\cdots \\ \vdots&\vdots&\vdots&\vdots&\ddots\\ \end{bmatrix} \]

妙哉妙哉。然后差分约束即可。

代码如下:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e6+10,M=2e6+10;

int head[N],nxt[M],edge[M],ver[M],tot;
void add(int x,int y,int z){
    ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;
}

ll d[610];
int a[310][310],b[310][310],n,m,cnt[610];
bool v[N];
deque<int>q;//spfa优化
bool spfa(){
    memset(v,0,sizeof(v)),memset(cnt,0,sizeof(cnt)),memset(d,0x3f,sizeof(d));
    d[1]=0,q.push_back(1);//v[1]=1;
    while(q.size()){
        int x=q.front();q.pop_front();
        ++cnt[x],v[x]=0;
        if(cnt[x]>n+m)return 0;
        for(int i=head[x];i;i=nxt[i]){
            int y=ver[i];
            if(d[y]>d[x]+edge[i]){
                d[y]=d[x]+edge[i];
                if(!v[y]){//spfa优化
                    if(q.size()&&d[y]<d[q.front()])q.push_front(y);
                    else q.push_back(y);
                    v[y]=1;
                }
            }
        }
    }
    return 1;
}

int main(){
    int T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=1;i<n;i++)for(int j=1;j<m;j++)scanf("%d",&b[i][j]);
        memset(a,0,sizeof(a));
        for(int i=n;i;i--)for(int j=m;j;j--)a[i][j]=b[i][j]-a[i][j+1]-a[i+1][j]-a[i+1][j+1];
        for(int i=1;i<=n+m;i++)head[i]=0;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if((i+j)&1)add(i,j+n,1e6-a[i][j]),add(j+n,i,a[i][j]);
                else add(i,j+n,a[i][j]),add(j+n,i,1e6-a[i][j]);
        if(spfa()){
            puts("YES");
            for(int i=1;i<=n;i++){
                for(int j=1;j<=m;j++){
                    if((i+j)&1)a[i][j]+=d[j+n]-d[i];
                    else a[i][j]+=d[i]-d[j+n];
                    printf("%d ",a[i][j]);
                }
                puts("");
            }
        }else puts("NO");
    }
    return 0;
}

世界上有没有一种时间复杂度正确的判负环的方法?这题巨卡常,SPFA卡不卡完全看心情,Bellman-Ford常数太大了qwq。

SPFA的优化听说也是假的,反向优化到指数级别qwq,能过一题是一题

posted @ 2024-10-04 18:35  lichenyu_ac  阅读(10)  评论(0)    收藏  举报