题解:P10499 开关问题
前置芝士:高斯消元、异或。
思路
不难发现灯的开关状态与异或有关。设
然后我们可以把灯的状态转化成异或方程组来做。
首先我们要知道什么可以控制一盏灯。能控制它的除了题目中给定的,还有它自己。
很显然每个开关最多被打开一次,设开关是否被打开为
然后就是这个题中最关键的方程了:
其中
它的意思是:如果能控制第
因为
对于每一个
这个高斯消元还不大一样。因为正常的高斯消元是求和,但是这个是异或,因此我们需要单独写,具体可以看代码。
主要的不同是:
- 不用取模。
- 原有的加减法运算全部改为异或。
如何计算答案?
如果在一个方程中出现了
- 如果
,说明这个方程没有约束,多一个自由元,自由元可以取 或 ,于是答案乘 。 - 反之,等式不成立,无解。
答案显然初始为
#include<bits/stdc++.h>
using namespace std;
int s[29],e[29],a[29][30],b[29];
int T,n;
int main(){
int T;
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)a[i][j]=0;
}
for(int i=1;i<=n;i++)cin>>s[i];
for(int i=1;i<=n;i++)cin>>e[i];
for(int i=1;i<=n;i++)a[i][n+1]=s[i] xor e[i];
while(1){
int x,y;
cin>>x>>y;
if(x==0&&y==0)break;
a[y][x]=1;
}
for(int i=1;i<=n;i++)a[i][i]=1;
for(int i=1;i<=n;i++){
int t=i;
for(int j=i+1;j<=n;j++){
if(a[j][i]>a[t][i])t=j;
}
swap(a[t],a[i]);
if(a[i][i]==0)continue;
for(int j=i+1;j<=n;j++){
int x=a[j][i];
for(int k=i;k<=n+1;k++){
a[j][k]^=(a[i][k]*x);
}
}
}
bool flag=0;
int ans=1;
for(int i=1;i<=n;i++){
int pos=0;
for(int j=1;j<=n;j++){
if(a[i][j]){
pos=j;
break;
}
}
if(pos==0)continue;
for(int j=i+1;j<=n;j++){
if(a[j][pos]){
for(int k=pos;k<=n+1;k++){
a[j][k]^=a[i][k];
}
}
}
}
for(int i=1;i<=n;i++){
int sum=0;
for(int j=1;j<=n;j++){
if(a[i][j]!=0)sum++;
}
if(sum==0){
if(a[i][n+1]==0)ans*=2;
else flag=1;
}
}
if(flag)cout<<"-1"<<endl;
else cout<<ans<<endl;
}
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】