\(\cal T_1\) 矩阵
Description
有一个 \(n\times n\) 的矩阵,初始时所有位置上都是零。每次操作你可以选择若干行和若干列,然后把这些行列交点处的位置都变成 \(1\).
现在,你需要在不超过 \(Q\) 次操作内,使得 \((i,j)\) 是零当且仅当 \(j\leqslant i\leqslant j+1\).
例如 \(n=5\) 时,你需要得到如下的矩阵:
01111
00111
10011
11001
11100
\(n\leqslant 3000,Q=26\).
Solution
构造一生之敌。
首先可以简化这个问题,先考虑只有对角线为零的情况:发现对角线可以表示为 \(x=y\),于是枚举行列二进制数的每一位 \(k\),将 "行的第 \(k\) 位为零,列的第 \(k\) 位为 \(1\)","行的第 \(k\) 位为 \(1\),列的第 \(k\) 位为零" 的下标全置为 \(1\),那么最后只有对角线不会被置为 \(1\).
但是现在我们还要维护对角线下面一格。不妨将图形 "缩放" 一下,大概地 将上下两格缩成一格,不就又成一条对角线了嘛?观察得知,奇偶性相同的列的格子缩起来比较符合对角线,因为这样分类能恰好将两个零缩成一个格子,以奇数列为例,就是一二行、三四行……为一格。于是可以将 \(n\times n\) 的图形大概地分成两个 \(n/2\times n/2\) 的图形,总操作次数在 \(4\log n\) 级别,这是过不了的。
观察数据范围,我们发现 \(\text{C}(Q/2,6)>n/2\),这意味着如果用 \(1\) 的个数为 \(6\) 个的十三位二进制数给行列重标号是完全足够的!二进制 \(1\) 的个数相等的数字有什么用呢?这意味着,如果数字 \(x,y\) 不同,那么一定存在一个二进制位 \(k\),满足 \(x\) 的第 \(k\) 位为零,\(y\) 的第 \(k\) 位为 \(1\)。也就是说,我们不再用讨论行列的 \(0,1\) 情况了。于是操作数正好是 \(2\times 13=26\).
Code
# include <cstdio>
# include <cctype>
# define print(x,y) write(x), putchar(y)
template <class T>
inline T read(const T sample) {
T x=0; char s; bool f=0;
while(!isdigit(s=getchar())) f|=(s=='-');
for(; isdigit(s); s=getchar()) x=(x<<1)+(x<<3)+(s^48);
return f? -x: x;
}
template <class T>
inline void write(T x) {
static int writ[50], w_tp=0;
if(x<0) putchar('-'), x=-x;
do writ[++w_tp]=x-x/10*10, x/=10; while(x);
while(putchar(writ[w_tp--]^48), w_tp);
}
# include <vector>
# include <iostream>
# include <algorithm>
using namespace std;
const int maxn = 1505;
vector <int> vec[2];
int n,Ref[maxn],bit,N,M,Bit,_bit;
struct node { int x,y; } s[maxn];
inline void handleTask(int delta) {
for(int b=0;b<13;++b) if((bit>>b&1) && !(Bit>>b&1)) {
vec[0].clear(); vec[1].clear();
for(int i=1;i<=N;++i) if(!(Ref[i]>>b&1)) {
if(s[i].x) vec[0].emplace_back(s[i].x);
if(s[i].y) vec[0].emplace_back(s[i].y);
}
if(delta) vec[0].emplace_back(1);
sort(vec[0].begin(),vec[0].end());
vec[0].erase(unique(vec[0].begin(),vec[0].end()),vec[0].end());
for(int i=1;i<=M;++i) if(Ref[i]>>b&1)
vec[1].emplace_back((i<<1)-1+delta);
printf("%d %d",int(vec[0].size()),int(vec[1].size()));
for(int d=0;d<2;++d) for(const auto& i:vec[d])
putchar(' '), write(i); puts("");
}
}
int main() {
n=read(9), read(9); int idx=0; Bit=(1<<13)-1;
for(int i=0, lim=1<<13; i<lim; ++i)
if(__builtin_popcount(i)==6) {
Ref[++idx]=i, bit|=i, Bit&=i;
if(idx==(n+1>>1)) break;
else _bit = bit;
}
idx=0; for(int i=0;i<13;++i)
if((bit>>i&1) && !(Bit>>i&1)) ++ idx;
(n&1)? swap(bit,_bit): void(); for(int i=0;i<13;++i)
if((bit>>i&1) && !(Bit>>i&1)) ++ idx;
print(idx,'\n');
for(int j=1;j<=n;j+=2)
s[j+1>>1] = (node){j,j+1<=n? j+1: 0};
(n&1)? swap(bit,_bit): void();
N=M=n+1>>1; handleTask(0);
for(int j=2;j<n;j+=2)
s[j>>1] = (node){j,j+1};
if(n&1) s[N=(n+1>>1)] = (node){1,0}, M=n>>1;
else s[N=(n>>1)] = (node){n,0}, M=n>>1;
(n&1)? swap(bit,_bit): void(); handleTask(1);
return 0;
}
\(\cal T_2\)
Description
Solution
Code
\(\cal T_3\)
Description
Solution
Code