[TJOI2008] 彩灯 (线性基)

[TJOI2008] 彩灯

题目描述

Peter女朋友的生日快到了,他亲自设计了一组彩灯,想给女朋友一个惊喜。已知一组彩灯是由一排N个独立的灯泡构成的,并且有M个开关控制它们。从数学的角度看,这一排彩灯的任何一个彩灯只有亮与不亮两个状态,所以共有\(2^N\)个样式。由于技术上的问题,Peter设计的每个开关控制的彩灯没有什么规律,当一个开关被按下的时候,它会把所有它控制的彩灯改变状态(即亮变成不亮,不亮变成亮)。假如告诉你他设计的每个开关所控制的彩灯范围,你能否帮他计算出这些彩灯有多少种样式可以展示给他的女朋友?

注: 开始时所有彩灯都是不亮的状态。

输入输出格式

输入格式:

每组测试数据第一行为两个整数N和M,用空格隔开。紧接着是有M行,每行都是一个长度为N的字符串,表示一个开关控制彩灯的范围(N盏灯),如果第i个字母是大写字母’O’,则表示这个开关控制第i盏灯,如果第i个字母是大写字母’X’,则表示这个开关不控制此灯。

输出格式:

输出这些开关和彩灯可以变换出来的样式数目。由于这个值可能会很大,请求出它对于整数2008的余数。

输入输出样例

输入样例#1:

2 3
OO
XO
OX

输出样例#1:
4

说明

可见样例中第一个开关控制了所有的彩灯,而后两个开关分别控制了第一个和第二个彩灯,这样我们可以只用后两个开关控制彩灯,可以变换出来所有的\(2^2\)个状态。

30%的数据中,N和M不超过15。

另外有40%的数据中,N和M有一个为50

100%的数据中,N和M不超过50。

Solution

线性基板子题

对于每一个开关,我们可以看成一个0/1串,初始是一个全部为0的串,要求经过这些开关的操作后,出现的不同的0/1串的个数

终点就是不同这两个字,这就决定了我们可以使用线性基来解决这道题

首先了解一下线性基的性质对于两个数字a,b,可以有0,a,b,a^b四种情况
把b换成a^b依然如此

线性基内的元素是不重复的

那么我们就可以把这些0/1串换成10进制后丢到线性基里面去,然后统计线性基内元素个数
在这里稍微讲一下线性基的原理

线性基可以说是一种容器,并且对于每一位都有一个数,这个数一定保证自己所在的这一位为1
我们开一个数组记录线性基,对于每一个数x我们都对它的每一位从高到低进行一遍扫描,与线性基中这一位去匹配
如果线性基中这一位为空,我们就把x加入这一位中,然后就不用做下去了
如果线性基中这一位有值,我们就用x去xor这个数,表示消去这一位,知道出现第一种情况
这种方法就保证了线性基内元素的不重复性
除此之外,线性基还有三条最重要的性质

  1. 线性基能相互异或得到原集合的所有相互异或得到的值
  2. 线性基是满足性质1的最小的集合
  3. 线性基没有异或和为0的子集

对于第1,2条性质,不需要太多解释,在这里主要证明一下第三条性质

证明:假设有\(a_1\bigoplus a_2\bigoplus ... \bigoplus a_n=0\),那么\(a_1\)一定可以由\(a_2\bigoplus ... \bigoplus a_n\)表示,那么我们把\(a1\)从线性基中删除依然可以异或除原来可以异或的元素,并且比原来的元素个数还要少,这样原来的线性基就与第二条性质最小集合相违背,所以假设不成立

下面是线性基构造代码

void init (lol box) {
    for(int i=50;i>=0;i--) {
        if(!(box>>i&1)) continue;
        if(!arr[i]) {++cnt,arr[i]=box;break;}
        else box^=arr[i];
    }
}

我们知道,线性基内的元素都是由外界元素异或出来的,那么对于线性基内每个元素,我们都有选/不选两种情况,所以\(Ans=1<<cnt\)

Code

#include<bits/stdc++.h>
#define lol long long
using namespace std;
const int N=51,mod=2008;
int cnt;
lol arr[N];
void init (lol box) {
    for(int i=50;i>=0;i--) {
        if(!(box>>i&1)) continue;
        if(!arr[i]) {++cnt,arr[i]=box;break;}
        else box^=arr[i];
    }
}
int main()
{
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) {
        char s[N]; scanf("%s",s);
        int len=strlen(s); lol x=0;
        for(int i=0;i<len;i++) x+=(1ll<<(n-i))*(s[i]=='O');
        init(x);
    }
    printf("%lld\n",1ll<<cnt);
    return 0;
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

原文地址:https://www.cnblogs.com/real-l/p/9639498.html

时间: 2024-10-29 16:28:54

[TJOI2008] 彩灯 (线性基)的相关文章

【题解】 luogu 3857 [TJOI2008]彩灯 (线性基)

luogu3857,懒得复制 Solution: 裸的线性基,往里面添加数,记录添加个数\(sum\),快速幂输出\(2^{sum}\)即可 Code: //It is coded by Ning_Mew on 5.30 #include<bits/stdc++.h> #define LL long long using namespace std; const int maxn=70,MOD=2008; int n,m; LL s[maxn],x[maxn],ans=0; LL read()

P3857 [TJOI2008]彩灯(线性基)

题目链接:https://www.luogu.org/problem/P3857 解题报告: 给出一个序列,让你求出异或后有多少种可能的情况. 将给的数插入到线性基中,最后答案即为$(1LL<<res)%2008$,res为线性基的种类数. AC代码: 1 #include<vector> 2 #include<cstdio> 3 #include<iostream> 4 #include<cmath> 5 #include<queue&g

[TJOI2008]彩灯

题目描述 Peter女朋友的生日快到了,他亲自设计了一组彩灯,想给女朋友一个惊喜.已知一组彩灯是由一排N个独立的灯泡构成的,并且有M个开关控制它们.从数学的角度看,这一排彩灯的任何一个彩灯只有亮与不亮两个状态,所以共有2N个样式.由于技术上的问题,Peter设计的每个开关控制的彩灯没有什么规律,当一个开关被按下的时候,它会把所有它控制的彩灯改变状态(即亮变成不亮,不亮变成亮).假如告诉你他设计的每个开关所控制的彩灯范围,你能否帮他计算出这些彩灯有多少种样式可以展示给他的女朋友? 注: 开始时所有

Xor HYSBZ - 2115 (线性基)

Xor HYSBZ - 2115 题意:给一个树,求1到n的最长路径.这里的路径定义为异或和. 线性基~~ 1 #include <bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 struct LiBase{ 5 ll a[63]; 6 //初始化 7 void init(){ 8 memset(a,0,sizeof(a)); 9 } 10 //插入 11 bool insert_(ll x){ 12 for(int

线性基小节

1.线性基的异或集合中每个元素的异或方案唯一. 2.线性基二进制最高位互不相同. 3.线性基中元素互相异或,异或集合不变. 摘自百度文库 线性基能相互异或得到原集合的所有相互异或得到的值. 线性基是满足性质1的最小的集合 线性基没有异或和为0的子集. 证明: 反证法:设线性基S={a1,a2...,an}: 若有子集a1^a2^...^at=0,则a1=a2^a3^...^at,则舍弃a1后一定能通过剩余的元素异或出所有需要a1参与异或的值.设Y=a1^X,因为{a1,a2,...,an}是一组

[BeiJing2011]元素[贪心+线性基]

2460: [BeiJing2011]元素 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1245  Solved: 652[Submit][Status][Discuss] Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们已经掌握了用魔法矿石炼制法杖的技术.那时人们就认识到,一个法杖的法力取决于使用的矿石.一般地,矿石越多则法力越强,但物极必反:有时,人们为了获取更强的法力而使用了很多矿石,却在炼制过程中

BZOJ 3105: [cqoi2013]新Nim游戏 [高斯消元XOR 线性基]

以后我也要用传送门! 题意:一些数,选择一个权值最大的异或和不为0的集合 终于有点明白线性基是什么了...等会再整理 求一个权值最大的线性无关子集 线性无关子集满足拟阵的性质,贪心选择权值最大的,用高斯消元判断是否和已选择的线性相关 每一位记录pivot[i]为i用到的行 枚举要加入的数字的每一个二进制为1的位,如果有pivot[i]那么就异或一下(消元),否则pivot[i]=这个数并退出 如果最后异或成0了就说明线性相关... #include <iostream> #include &l

【BZOJ2844】albus就是要第一个出场 线性基 高斯消元

#include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/43456773"); } 题意:需要注意的是空集(0)是天生被包括的,我为了这个WA了好久~拍了好久,醉了好久~ 题解: 首先有一个我并不知道是为什么(甚至不知道它对不对)的性质: 每一种权值会出现2的自由元(n-线性基个数)次方 次. 感性

[bzoj 2460]线性基+贪心

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2460 网上很多题目都没说这个题目的证明,只说了贪心策略,我比较愚钝,在大神眼里的显然的策略还是想证明一下才安心--所以这里记录一下证明过程. 贪心策略:按魔力值从大到小排序,从大往小往线性基里插,如果成功插入新元素,就选这个,如果插不进去,就不选这个. 证明: 设有n个材料,每个材料的属性值是x[1],x[2],...,x[n],魔力值是v[1],v[2],...,v[n],这里假设v已