bzoj4851: [Jsoi2016]位运算
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4851: [Jsoi2016]位运算相关的知识,希望对你有一定的参考价值。
4851: [Jsoi2016]位运算
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 12 Solved: 7
[Submit][Status][Discuss]
Description
JYY最近在研究位运算。他发现位运算中最有趣的就是异或(xor)运算。对于两个数的异或运算,JYY发现了一个
结论:两个数的异或值为0当且仅当他们相等。于是JYY又开始思考,对于N个数的异或值会有什么性质呢?
【问题描述】
JYY想知道,如果在0到R-1的范围内,选出N个不同的整数,并使得这N个整数的异或值为0,那么一共有多少种选择
的方法呢?(选择的不同次序并不作重复统计,请参见样例)JYY是一个计算机科学家,所以他脑海里的R非常非常
大。为了能够方便的表达,如果我们将R写成一个0-1串,那么R是由一个较短的0-1串S重复K次得到的。比如,若S=
“101”,K=2,那么R的2进制表示则为“101101”。由于计算的结果会非常大,JYY只需要你告诉他选择的总数对1
0^9+7取模的结果即可
Input
第一行包含两个正整数N和K。
接下来一行包含一个由0和1组成的字符串S。
我们保证S的第一个字符一定为1。
3<=N<=7,1<=k<=10^5,1<=|S|<=50
Output
一行一个整数,表示选择的方案数对10^9+7取模的值。
Sample Input
3 1
100
100
Sample Output
1
对于第一个样例, 唯一的一种选择方法是选择 {1, 2, 3}。
对于第一个样例, 唯一的一种选择方法是选择 {1, 2, 3}。
HINT
Source
从高到低确定n个数的每一位 填的过程中保持n个数从小到大 每一位1的个数都要是偶数
填完前i位后 n个数可能有相等 形成若干段区间 记一下区间间隔的位置
因为要求小于R 再记一下最大的数是否等于s的前i位
然后分i+1位是0/1转移一下
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mo 1000000007 5 using namespace std; 6 int n,k; 7 char s[1000]; 8 struct mat{ 9 int m[130][130]; 10 mat(){ 11 for (int i=0;i<(1<<n);i++) 12 for (int j=0;j<(1<<n);j++) 13 m[i][j]=0; 14 } 15 } a[2]; 16 mat mul(mat a,mat b){ 17 mat re; 18 for (int i=0;i<(1<<n);i++) 19 for (int j=0;j<(1<<n);j++) 20 for (int k=0;k<(1<<n);k++){ 21 re.m[i][j]+=1ll*a.m[i][k]*b.m[k][j]%mo; 22 if (re.m[i][j]>=mo) re.m[i][j]-=mo; 23 } 24 return re; 25 } 26 int main(){ 27 scanf("%d%d%s",&n,&k,&s);int len=strlen(s); 28 29 for (int zt=0;zt<(1<<n);zt++){ 30 for (int zy=0;zy<(1<<n);zy++){ 31 int td=0; 32 for (int i=1;i<=n;i++) if (zy&(1<<(i-1))) td++; 33 if (td&1) continue; 34 35 if (zt&1){ 36 int ha=0; 37 for (int i=n;i;i--){ 38 if (zy&(1<<(i-1))) ha=1; 39 if (zt&(1<<(i-1))) break; 40 } 41 if (ha) continue; 42 } 43 44 td=0; 45 for (int i=1;i<n;i++) if ((zy&(1<<(i-1)))&&!(zy&(1<<i))){ 46 if (!(zt&(1<<i))) td=1; 47 } 48 if (td) continue; 49 50 int go=zt; 51 for (int i=1;i<n;i++) if (!(zy&(1<<(i-1)))&&(zy&(1<<i))) 52 go|=(1<<i); 53 a[0].m[go][zt]++; 54 } 55 } 56 57 for (int zt=0;zt<(1<<n);zt++){ 58 for (int zy=0;zy<(1<<n);zy++){ 59 int td=0; 60 for (int i=1;i<=n;i++) if (zy&(1<<(i-1))) td++; 61 if (td&1) continue; 62 63 int ha=0; 64 for (int i=n;i;i--){ 65 if (zy&(1<<(i-1))) ha=1; 66 if (zt&(1<<(i-1))) break; 67 } 68 69 td=0; 70 for (int i=1;i<n;i++) if ((zy&(1<<(i-1)))&&!(zy&(1<<i))){ 71 if (!(zt&(1<<i))) td=1; 72 } 73 if (td) continue; 74 75 int go=zt; 76 for (int i=1;i<n;i++) if (!(zy&(1<<(i-1)))&&(zy&(1<<i))) 77 go|=(1<<i); 78 if (!ha&&(go&1)) go^=1; 79 a[1].m[go][zt]++; 80 } 81 } 82 83 mat td,ret,lj,init; 84 for (int i=0;i<(1<<n);i++) td.m[i][i]=ret.m[i][i]=1; 85 for (int i=0;i<len;i++) td=mul(a[s[i]-‘0‘],td); 86 for (lj=td;k;k/=2,lj=mul(lj,lj)) if (k&1) 87 ret=mul(ret,lj); 88 init.m[1][0]=1; 89 ret=mul(ret,init); 90 printf("%d\n",ret.m[(1<<n)-2][0]); 91 }
以上是关于bzoj4851: [Jsoi2016]位运算的主要内容,如果未能解决你的问题,请参考以下文章