题解:P10315 [SHUPC 2024] 原神,启动!
简述题面
给定
第
每次操作可以选一个方碑,使它切换到下一种状态。但方碑有时会相互影响,当某一方碑被操作时,能被它影响的方碑也会切换到下一种状态(
思路
很典的高斯消元题目,我们设第
其中的
将各式的
于是我们便可以用高斯消元直接求解。
代码实现
因为我们平时所做的高斯消元一般是浮点型计算,而本题需要取模,所以可能会有一些实现细节的不同。
我们发现我们在消元期间做除法的目的就是让某一行的某个参
但最后也有绕不开的除法(在高斯消元逐步递推
:::success[AC Code]
#include<bits/stdc++.h>
#define int long long
using namespace std;
inline long long power(long long a,long long b,long long m){
long long res=1;
for (;b;b>>=1,a=(a*a)%m)
if (b&1) res=(res*a)%m;
return res;
}
const int N=105;
int n,m;
int a[N][N];
int s[N],t[N];
inline int Gauss(int (*a)[N],int n){
int rk=1;
for (int j=1;j<=n;j++){
int h=rk;
for (int i=rk+1;i<=n;i++)
if (abs(a[i][j])>abs(a[h][j])) h=i;
if (a[h][j]==0) continue;
for (int l=j;l<=n+1;l++)
swap(a[j][l],a[h][l]);
for (int i=rk+1;i<=n;i++){
if (a[i][j]==0) continue;
int g=__gcd(a[i][j],a[rk][j]);
int tmp1=a[rk][j]/g;
int tmp2=a[i][j]/g;
for (int l=j;l<=n+1;l++)
a[i][l]=((a[i][l]*tmp1-a[rk][l]*tmp2)%m+m)%m;//通分后消元
}
++rk;
}
for (int i=rk;i<=n;i++)
if (a[i][n+1]) return -1;
for (int i=n;i>=1;i--){
for (int j=i+1;j<=n;j++)
a[i][n+1]=((a[i][n+1]-a[i][j]*a[j][n+1])%m+m)%m;
a[i][n+1]=(a[i][n+1]*power(a[i][i],m-2,m))%m;//用逆元做模数除法
}
return 1;
}
int dx[4]={0,1,0,-1};
int dy[4]={1,0,-1,0};
inline void solve(){
memset(a,0,sizeof(a));
cin>>n>>m;
for (int i=1,k;i<=n;i++){
cin>>k;
a[i][i]=1;
for (int j=1,x;j<=k;j++){
cin>>x;
a[x][i]=1;//第 i 号石碑可以影响第 x 号石碑
}
}
for (int i=1;i<=n;i++) cin>>s[i],a[i][n+1]=-s[i];
for (int i=1;i<=n;i++) cin>>t[i],a[i][n+1]=((a[i][n+1]+t[i])%m+m)%m;//注意模数减法的实现
int res=Gauss(a,n);
if (res==-1) cout<<"niuza",exit(0);//无解情况
for (int i=1;i<=n;i++)
cout<<a[i][n+1]<<' ';
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T=1;
while (T--) solve();
return 0;
}
:::