题解 数学题

传送门

我就静静的看着出题人用一个我不会的东西解释另一个我不会的东西

首先可以 bitset 卡常+线性基模拟得到 50 pts
然后重点来优化如何快速判断一个数的每一位被翻转后能否插入没有这个数的线性基
对这是个不需要删除操作的做法
先建出原序列的线性基,记录每个线性基内的数异或过谁以及线性基外的数能被哪些基底构成
然后对于第 \(i\) 行,问题等价于问 \(x\oplus (1\ll j)\) 能否插入删去 \(x\) 的线性基
\(x\) 不在线性基中则判断 \((1\ll j)\) 能否插入即可,可以高斯消元预处理
\(x\) 在线性基中再分类讨论
\(x\) 作为基底构成过别的数删了等于没删
否则若 \((1\ll j)\) 能被表示需要考虑它是不是被 \(x\) 表示出来的,查 \((1\ll j)\) 的组成即可
复杂度 \(O(\frac{n^3}{w})\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
//#define int long long

int n, m;
char mp[1010][1010];

namespace force{
	int base[N], tem[1010][1010];
	int insert(int t) {
		for (int i=1; i<=m; ++i) if (tem[t][i]) {
			if (!base[i]) {base[i]=t; return 1;}
			else {
				for (int j=1; j<=m; ++j) tem[t][j]^=tem[base[i]][j];
			}
		}
		return 0;
	}
	int query() {
		int cnt=0;
		for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) tem[i][j]=mp[i][j];
		for (int i=1; i<=m; ++i) base[i]=0;
		for (int i=1; i<=n; ++i) cnt+=insert(i);
		return cnt;
	}
	void solve() {
		int lim=query();
		for (int i=1; i<=n; ++i) {
			for (int j=1; j<=m; ++j) {
				mp[i][j]^=1;
				int t=query();
				if (t<lim) printf("-");
				else if (t>lim) printf("+");
				else printf("0");
				mp[i][j]^=1;
			}
			printf("\n");
		}
	}
}

namespace task1{
	int base[N], bkp_base[N], cnt, bkp_cnt;
	bitset<1010> mp2[1010], tem[1010], bkp_tem[1010];
	void clear() {
		cnt=0;
		for (int i=1; i<=n; ++i) tem[i]=mp2[i];
		for (int i=1; i<=m; ++i) base[i]=0;
	}
	void save() {
		bkp_cnt=cnt;
		for (int i=1; i<=n; ++i) bkp_tem[i]=tem[i];
		for (int i=1; i<=m; ++i) bkp_base[i]=base[i];
	}
	void recover() {
		cnt=bkp_cnt;
		for (int i=1; i<=n; ++i) tem[i]=bkp_tem[i];
		for (int i=1; i<=m; ++i) base[i]=bkp_base[i];
	}
	void insert(int t) {
		for (int i=tem[t]._Find_first(); i<1010; i=tem[t]._Find_next(i)) {
			if (!base[i]) {base[i]=t, ++cnt; return ;}
			else tem[t]^=tem[base[i]];
		}
	}
	int query() {
		clear();
		for (int i=1; i<=n; ++i) insert(i);
		return cnt;
	}
	void solve() {
		for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp2[i][j]=(mp[i][j]==1);
		int lim=query();
		for (int i=1; i<=n; ++i) {
			clear();
			for (int j=1; j<=n; ++j) if (i!=j) insert(j);
			save();
			for (int j=1; j<=m; ++j) {
				recover();
				tem[i].flip(j);
				insert(i);
				if (cnt<lim) printf("-");
				else if (cnt>lim) printf("+");
				else printf("0");
			}
			printf("\n");
		}
	}
}

namespace task{
	int basis[N], siz;
	bool in_basis[N], able[N];
	bitset<1010> tem[1010], form[1010];
	struct matrix{
		bool isable[1010];
		bitset<1010> a[1010], form[1010];
		inline bitset<1010>& operator[] (int t) {return a[t];}
		void put() {
			cout<<"---mat---"<<endl;
			for (int i=1; i<=m; ++i) {for (int j=1; j<=m; ++j) cout<<a[i][j]; cout<<endl;}
			cout<<"---form---"<<endl;
			for (int i=1; i<=m; ++i) {for (int j=1; j<=m; ++j) cout<<form[i][j]; cout<<endl;}
		}
		void gauss() {
			for (int i=1; i<=m; ++i) {
				for (int j=i; j<=m; ++j)
					if (a[j][i]) {swap(a[i], a[j]); swap(form[i], form[j]); break;}
					else if (!a[i].none() && a[j].none()) swap(a[i], a[j]), swap(form[i], form[j]);
				if (!a[i][i]) continue;
				for (int j=1; j<=m; ++j) if (i!=j && a[j][i]) a[j]^=a[i], form[j]^=form[i];
			}
			for (int i=1; i<=m; ++i) if (a[i][i] && a[i].count()==1) isable[i]=1;
		}
		bool able(int i) {return isable[i];}
	}mat;
	void insert(int t) {
		form[t][t]=1;
		for (int i=tem[t]._Find_first(); i<1010; i=tem[t]._Find_next(i)) {
			if (!basis[i]) {basis[i]=t; in_basis[t]=1; ++siz; return ;}
			else tem[t]^=tem[basis[i]], form[t]^=form[basis[i]];
		}
		for (int i=form[t]._Find_first(); i<1010; i=form[t]._Find_next(i)) able[i]=1;
	}
	void solve() {
		for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) tem[i][j]=(mp[i][j]==1);
		for (int i=1; i<=n; ++i) insert(i);
		for (int i=1; i<=m; ++i) if (basis[i]) mat[i]=tem[basis[i]], mat.form[i]=form[basis[i]]; //, cout<<tem[basis[i]]<<endl;
		mat.gauss(); //mat.put();
		for (int i=1; i<=n; ++i) {	
			for (int j=1; j<=m; ++j) {
				if (!in_basis[i]) printf("%c", mat.able(j)?'0':'+');
				else {
					if (able[i]) printf("%c", mat.able(j)?'0':'+');
					else {
						if (!mat.able(j)) printf("0");
						else printf("%c", mat.form[j][i]?'-':'0');
					}
				}
			}
			printf("\n");
		}
	}
}

signed main()
{
	freopen("math.in", "r", stdin);
	freopen("math.out", "w", stdout);

	scanf("%d%d", &n, &m);
	for (int i=1; i<=n; ++i) {
		scanf("%s", mp[i]+1);
		for (int j=1; j<=m; ++j) mp[i][j]^=48;
	}
	// force::solve();
	// task1::solve();
	task::solve();
	
	return 0;
}
posted @ 2022-02-16 20:14  Administrator-09  阅读(1)  评论(0编辑  收藏  举报