ZR省选十连测day6 矩阵
题目描述
题解
正解是刚好卡到 26 次的,说一个最多 24 次的做法。
首先考虑只要求对角线为 0 的情况,相当于要把所有 i ≠ j i\neq j i=j 的位置填上。考虑一次操作相当于一个行标和列标匹配的过程,我们可以考虑用类似CDQ分治的方法,在线段树上每次让前一半标号做行,后一半标号做列,这样可以在 2 n 2n 2n 次操作内刚好填满所有 i < j i<j i<j 的位置,而 i > j i>j i>j 的位置反过来做即可。
然后发现这个过程其实很浪费,可以让线段树上同一深度的操作同时做,也就是并行计算,因为我们只要 i ≠ j i\neq j i=j 嘛。这样操作次数就是 log n \log n logn 了,其本质上和二进制分组是一样的。
然后考虑这道题的情况,对角线下面还有一条 0。这其实就是把我们原来要填的 i > j i>j i>j 的下三角往下挪了一格,如果我们是原始的CDQ分治做法的话,可以简单地在做第二遍的时候把它简单重标号一下,然后判掉出界的行标即可。
但是直接沿用到并行计算上面会有漏洞,因为把区间的操作并起来的时候会出现一个列标号区间拼在一个行标号区间前面,这样填出来就不合法。
正解的解决方法是把原矩阵奇偶分类(或叫黑白染色?),然后另找他法。其实不需要的,我们可以直接把两遍操作过程穿插在一起:
注意到重标号仅仅是把行标号-1,所以上面的过程全部换成原标号是这样的:
这样显然不会填到两条线,而且其它位置全都会填满。
总共操作次数是 2 log n 2\log n 2logn,最大为 24。
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long//God JZM!!
#define lll __int128//JZM RollInDark!!
#define uns unsigned
#define fi first
#define se second
#define IF (it->fi)
#define IS (it->se)
#define lowbit(x) ((x)&-(x))
#define END putchar('\n')
#define inline jzmyyds
using namespace std;
const int MAXN=3005;
const ll INF=1e16;
ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[50],lpt;
void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt)putchar(ptf[lpt--]^48);
if(c>0)putchar(c);
}
int n,tot,Q;
#define pii pair<int,int>
vector<pii>T,F;
struct step{set<int>r,c;};
vector<step>as;
int main()
{
n=read(),Q=read();
T.emplace_back(pii(1,n));
while(!T.empty()){
for(int o=0,e;o<2;o++){
e=o,as.resize(as.size()+1);
auto&st=as.back();
for(auto&lr:T){
int l=lr.fi,r=lr.se,mid=(l+r)>>1;
if(e^=1){
for(int i=l;i<=mid;i++)st.r.insert(i);
for(int i=mid+1;i<=r;i++)st.c.insert(i);
}else{
for(int i=l;i<=mid;i++)st.c.insert(i);
for(int i=mid+1;i<=r;i++)if(i<n)st.r.insert(i+1);
}
}
if(st.r.empty()||st.c.empty())as.pop_back();
}
F.clear();
for(auto&lr:T){
int l=lr.fi,r=lr.se,mid=(l+r)>>1;
if(mid>l)F.emplace_back(pii(l,mid));
if(r>mid+1)F.emplace_back(pii(mid+1,r));
}T.swap(F);
}
print(as.size());
for(auto&x:as){
print(x.r.size(),' '),print(x.c.size(),0);
for(int z:x.r)printf(" %d",z);
for(int z:x.c)printf(" %d",z);
END;
}
return 0;
}