bzoj4851: [Jsoi2016]位运算

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj4851: [Jsoi2016]位运算相关的知识,希望对你有一定的参考价值。

4851: [Jsoi2016]位运算

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 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

Sample Output

1
对于第一个样例, 唯一的一种选择方法是选择 {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 }
View Code





以上是关于bzoj4851: [Jsoi2016]位运算的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ4753: [Jsoi2016]最佳团体

bzoj2208: [Jsoi2010]连通数

BZOJ4753: [Jsoi2016]最佳团体

bzoj4753[Jsoi2016]最佳团体 分数规划+树形背包dp

bzoj1559: [JSOI2009]密码

bzoj 4754: [Jsoi2016]独特的树叶