专栏文章
P13052 [GCJ 2020 Qualification] Indicium 题解
P13052题解参与者 3已保存评论 5
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 5 条
- 当前快照
- 1 份
- 快照标识符
- @miooe5pw
- 此快照首次捕获于
- 2025/12/02 22:30 3 个月前
- 此快照最后确认于
- 2025/12/02 22:30 3 个月前
考虑一个矩阵主对角线会是什么样的排布。
首先,一个显然的事情是,不存在合法的方案,使得其主对角线是 ,不然最后一行一列的 就没地方放了。
那考虑 的情况。
一个比较简单的结论是:
对于任意正整数 ,都存在 ,满足 。
证明考虑归纳。 显然成立。对于 ,假设之前有一组 ,那么如果 ,那么就可以对 中较小的那个 。若 ,那么就可以让 ,这样 总体就要去掉 ,又回到上一种情况,再对较小的 即可。
按照以上方式,再进行一些微调,我们可以得到一组 。
然后我们考虑如何在这个主对角线的基础上构造。
首先被 占用的行列,剩余的两个 是可以确定的。
由于 是较为特殊的,所以我们钦定第一行为 (即在 的基础上,将 提到前面来)。
假如没有最后两行列,我们可以直接每行在上一行的基础上循环移位填入。
那现在这两行列较为特殊,我们其实也可以类似地填入。
下面以 为例。
初始是这样:
接下来我们填入 。按照原本的循环移位的思路,我们试着填在 的后面一个。
发现填到这里的时候爆了,我们跳过这一位。
接下来填 。
发现位置冲突了,并且 已经出现过,那么 自动向后一个填入。
接下来填 。
发现只是单纯的冲突了,我们这次跳过,但下面需要找机会补回来。
发现这一行对应我们没有填的列是可以填的,立刻补回来。后面正常填。
填 的时候,遇到冲突和解决冲突的过程是一样的。
若有之前冲突的没填的列,在这一行可以填,那就填;若当前列冲突,则向后一列再填,并压入一个栈,栈内都是跳过未填的列。
和 用相同的方式可以填完。
至于这样为什么一定能得到合法方案,我暂时还不会证明,但是它确实过了。如果你会的话可以评论区提出或私信我,我会给你磕头的。
此外注意一些无解的 corner cases。
尽管 ,时间复杂度却是 。
CPP#include<bits/stdc++.h>
#define N 55
#define ll long long
#define mod
using namespace std;
int n,m,ans[N][N],a[N];
bool fl[N][N];
void sol()
{
static int cas=0;
cin>>n>>m;
cout<<"Case #"<<++cas<<": ";
if(m<n||m==n+1||m==n*n-1||n==3&&m==5||n==3&&m==7)
{
cout<<"IMPOSSIBLE\n";
return;
}
int p=1,q=1,r=1;
m-=n;
while(m--)
{
if(q+r==n*2)
{
p++;
q-=n-2;
}
if(++q>r) swap(q,r);
}
if(p==r) swap(q,r);
if(p==q&&q!=r)
{
if(r==n) p++,r-=n-2;
q--,r++;
}
// cerr<<p<<','<<q<<','<<r<<'\n';
iota(a+1,a+n+1,1);
sort(a+1,a+n+1,[&](int x,int y){return x==p?1:y==p?0:x==q?1:y==q?0:x==r?1:y==r?0:x<y;});
memset(fl,0,sizeof(fl));
memset(ans,0,sizeof(ans));
ans[n-1][n-1]=q;
ans[n][n]=r;
fl[n-1][q]=fl[n][r]=1;
for(int id=1;id<=n;id++)
{
int x=a[id];
stack<int>st;
for(int i=1,j=id;i<=n;i++)
{
if(ans[i][i]==x) continue;
if(!st.empty()&&!ans[i][st.top()])
{
ans[i][st.top()]=x;
fl[st.top()][x]=1;
st.pop();
continue;
}
while(ans[i][j]||fl[j][x])
{
// cerr<<i<<','<<j<<' ';
if(!fl[j][x]) st.push(j);
j=j%n+1;
}
ans[i][j]=x;
fl[j][x]=1;
}
}
cout<<"POSSIBLE\n";
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
cout<<ans[i][j]<<' ';
}
cout<<'\n';
}
}
int main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin>>t;
while(t--) sol();
return 0;
}
相关推荐
评论
共 5 条评论,欢迎与作者交流。
正在加载评论...