【高斯消元】AcWing 227. 小部件厂

不仅题意不太清楚而且实现过程还有一堆细节的题目。。Orz

分析

其实这题就是给你 \(m\) 个同余方程,然后有 \(n\) 个变量 \(x\)(其中 \(x\in [3, 9]\)),记第 \(i\) 个方程第 \(j\) 个变量 \(x_j\) (其中 \(x\in [3, 9]\))的个数为 \(a_j\)\(b_i\) 为两个给出的日子的间隔天数,则满足:

\[\left\{\begin{matrix} \sum_{j=1}^n a_{1, j} x_{1, j} \equiv b_1 \pmod 7 \\ \dots \\ \sum_{j=1}^n a_{n, j} x_{n, j} \equiv b_n \pmod 7 \end{matrix}\right. \]

看到这个形式,自然是考虑使用高斯消元来解决,如果得到的矩阵的秩为 \(n\)​,当然可以直接得到答案——由于 \(x\) 值域不大,直接对每个变量 \(X\) 进行值的枚举,如果出现了无解情况直接 return,若每个变量都有解就输出解即可。

但是情况没有这么简单,

  • 首先我们要判断:如果 \(m>n\)​,那么需要判断是否在 \([m+1, n]\)​​ 行出现矛盾,因为在高斯消元之后,\([m+1, n]\)​​ 必须是 \(0 = 0\) 的形式,不是则矛盾。

  • 其次,如果矩阵的秩\(<n\),因为高斯消元之后的矩阵会变为最简阶梯形,记每行的系数不为 \(0\) 的个数为 \(cnt_i\)

    那么对于如果 \(cnt_i = 0\),检查是否满足 \(0 = 0\);如果 \(cnt_i > 1\)​​,两个及以上的变量一定足够使这一行有解,跳过;如果 \(cnt_i = 1\),通过枚举该变量的值来检查是否有解,而在这个过程中,如果这个变量已经被求解过且值与现在求的不同,那么矛盾。

最简阶梯形矩阵例子:

\[\begin{pmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 2 & 3 \\ 0 & 0 & 0 & 0 \\ \end{pmatrix} \]

// Problem: 小部件厂
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/229/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)

#define int long long

inline int read(){
    int s=0; int x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    return s;
}

const int N=330, P=7;

int n, m;
int c[N][N], b[N];

map<string, int> mp;
void init(){
	mp["MON"]=1, mp["TUE"]=2;
	mp["WED"]=3, mp["THU"]=4;
	mp["FRI"]=5, mp["SAT"]=6;
	mp["SUN"]=7;
}

int get(string a, string b){
	return ((mp[b]-mp[a]+1)%P+P)%P;
}

int fpow(int x, int p){
	int res=1;
	for(; p; p>>=1, x=x*x%P) if(p&1) res=res*x%P;
	return res%P;
}

int inv(int x){
	return fpow(x, P-2);
}

int get(int x){
	return (x%P+P)%P;
}

int res[N];
void guass(){
	rep(i,1,n){
		rep(j,i,m) if(c[j][i]%P){
			rep(k,1,n) swap(c[i][k], c[j][k]);
			swap(b[i], b[j]);
		}
		rep(j,1,m){
			if(i==j) continue;
			int t=c[j][i]*inv(c[i][i])%P;
			rep(k,i,n) c[j][k]-=c[i][k]*t%P, c[j][k]=get(c[j][k]);
			b[j]-=b[i]*t;
			b[j]=get(b[j]);
		}
	}
	
	rep(row,n+1,m) if(b[row]) return puts("Inconsistent data."), void();
	// no fixed sol
	rep(pos,1,n) if(!c[pos][pos]){
		rep(i,1,n) res[i]=0;
		rep(i,1,n){
			int cnt=0, rec, p;
			rep(j,1,n) if(c[i][j]) cnt++, rec=c[i][j], p=j;
			if(cnt!=1){
				if(!cnt && b[i]) return puts("Inconsistent data."), void();
				continue;
			}
			
			bool ok=false;
			rep(val,3,9){
				int t=val*rec-b[i];
				if(t%P==0){
					if(res[p] && res[p]!=val) return puts("Inconsistent data."), void();
					res[p]=val;
					ok=true;
				}
			}
			
			if(!ok) return puts("Inconsistent data."), void();
		}
		return puts("Multiple solutions."), void();
	}

	bool ok=true;
	rep(i,1,n){
		int cnt=0, rec;
		rep(val,3,9){
			int t=val*c[i][i]-b[i];
			if(t%P) continue;
			cnt++, rec=val;
		}
		if(!cnt){
			puts("Inconsistent data.");
			return;
		}
		if(cnt>1) ok=false;
		else res[i]=rec;
	}
	
	if(!ok) return puts("Multiple solutions."), void();
	rep(i,1,n) printf("%lld ", res[i]);
	puts("");
}

void clear(){
	rep(i,1,m) rep(j,1,n) c[i][j]=0;
	rep(i,1,m) b[i]=0;
}

signed main(){	
	init();
	while(n=read(), m=read(), n || m){
		string s1, s2;
		rep(i,1,m){
			int k; k=read();
			cin>>s1>>s2;
			b[i]=get(s1, s2);

			while(k--){
				int ty; ty=read();
				c[i][ty]++;
			}
		}
		guass();
		clear();
	}
	
	return 0;
}
posted @ 2022-02-18 17:34  HinanawiTenshi  阅读(73)  评论(0编辑  收藏  举报