@xiaoziyao
2021-04-20T11:11:24.000000Z
字数 2768
阅读 1043
解题报告
P7515 [省选联考 2021 A 卷] 矩阵游戏解题报告:
给定大小为的矩阵,求生成任意一个满足条件的满足:
保证,。
可能是暗中送我退役的一道题,我要是把这个思路想下去做掉这道题,那我剩下的题用头打都能进队啊!!!!!!!!!!!!!!!!!!!!!!!!!!!!
技不如人,肝败吓疯。
首先不考虑,并钦定,不难发现可以生成一组解。
我们考虑通过调整某些位置的权值使得最后的解权值满足限制。
发现对某一行交替后的解仍然满足矩阵的限制;同理,对某一列交替后的解也仍然满足矩阵的限制。
不难发现任意一组解都可以被这样表示出来:
再考虑这一限制,不难发现把序列与序列看做未知量之后可以对其进行差分约束。
但是对于同号的不等式是很难进行差分约束的,考虑定义,
然后再次带入上面的解可以得到一个很优美的形式:
这样就可以进行差分约束了,复杂度:。
Bellman Ford被卡常了(需要特判才能过),迫不得已用了spfa/kk
#include<stdio.h>
#include<queue>
#include<vector>
#define inf 10000000000000000
using namespace std;
const int maxn=305,maxm=maxn*maxn*2;
int T,n,m,e;
int a[maxn][maxn],b[maxn][maxn],vis[maxn<<1],tot[maxn<<1];
vector<int>v[maxn<<1],w[maxn<<1];
long long dis[maxn<<1];
queue<int>q;
inline void add(int x,int y,int z){
v[x].push_back(y),w[x].push_back(z);
}
inline void limit(int x,int y,int v){
add(x,y,v);//v+x-y>=0
add(y,x,1000000-v);//v+x-y<=1000000
}
int spfa(){
while(!q.empty())
q.pop();
for(int i=1;i<=n+m;i++)
dis[i]=inf,tot[i]=0,vis[i]=0;
dis[1]=0,vis[1]=1,q.push(1);
while(!q.empty()){
int x=q.front();
tot[x]++;
if(tot[x]>n+m)
return 1;
q.pop();
for(int i=0;i<v[x].size();i++){
int y=v[x][i],z=w[x][i];
if(dis[y]>dis[x]+z){
dis[y]=dis[x]+z;
if(vis[y]==0)
vis[y]=1,q.push(y);
}
}
vis[x]=0;
}
return 0;
}
inline int calc(int x,int y){
return a[x][y]+(int)(((x+y)&1)? (dis[n+y]-dis[x]):(dis[x]-dis[n+y]));
}
int main(){
scanf("%d",&T);
while(T--){
e=0;
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
scanf("%d",&b[i][j]);
for(int i=2;i<=n;i++)
for(int j=2;j<=m;j++)
a[i][j]=b[i-1][j-1]-a[i-1][j-1]-a[i-1][j]-a[i][j-1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
if((i+j)&1)
limit(n+j,i,a[i][j]);
else limit(i,n+j,a[i][j]);
}
if(spfa()){
puts("NO");
for(int i=1;i<=n+m;i++)
v[i].clear(),w[i].clear();
continue;
}
puts("YES");
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
printf("%d%c",calc(i,j),j==m? '\n':' '),a[i][j]=0;
for(int i=1;i<=n+m;i++)
v[i].clear(),w[i].clear();
}
return 0;
}
省选联考A卷全部题解可见:2021省选联考A卷解题报告