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

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

分析

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

{j=1na1,jx1,jb1(mod7)j=1nan,jxn,jbn(mod7)

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

但是情况没有这么简单,

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

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

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

最简阶梯形矩阵例子:

(1000010000230000)

// 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 @   HinanawiTenshi  阅读(81)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
历史上的今天:
2021-02-18 【数据结构】线性基
点击右上角即可分享
微信分享提示