yk最近在研究位运算。
它发现除了xor,or,and外还有很多运算。
它新定义了一种运算符“#”。
具体地,可以由4个参数来表示。
ai,j表示
i#j。
其中i,j与a的值均∈[0,1]。
当然问题可以扩展为>1的情况,具体地,可以将两个数分解为p位,然后对于每一位执行上述的位运算,再将这个二进制串转化为十进制就可以了。
例如当 a0,0=a1,1=0,a0,1=a1,0=1时,3#4在p=3时等于7,2#3在p=4时等于1(实际上就是异或运算)。
现在lyk想知道的是,已知一个数列b。
它任意选取一个序列c,满足 c1<c2<...<ck,其中1≤c1且ck≤n ,这个序列的价值为 bc1 # bc2 #...# bck 的平方。
这里我们假设k是正整数,因此满足条件的c的序列一定是 2n−1 。lyk想知道所有满足条件的序列的价值总和是多少。
例如样例中,7个子集的价值分别为1,1,4,4,9,9,0。总和为28。
由于答案可能很大,只需对1,000,000,007取模即可。
Input
第一行两个整数n(1<=n<=50000),p(1<=p<=30)。 第二行4个数表示a0,0,a0,1,a1,0,a1,1。(这4个数都∈{0,1}) 第三行n个数bi(0<=bi<2^p)。
Output
一行表示答案。
Input示例
3 30 0 1 1 0 1 2 3
Output示例
28
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 5e4 + 10;
const int MOD = 1e9 + 7;
int n, p;
int b[MAXN];
int a[2][2];
int dp[MAXN][2][2];
int get(int x, int y)
{
memset(dp, 0, sizeof(dp));
for (int k = 1; k <= n; k++)
{
int n1 = (b[k] >> x) & 1;
int n2 = (b[k] >> y) & 1;
++dp[k][n1][n2];
dp[k][n1][n2] %= MOD;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
dp[k][a[i][n1]][a[j][n2]] = (dp[k][a[i][n1]][a[j][n2]] + dp[k - 1][i][j]) % MOD;
dp[k][i][j] = (dp[k][i][j] + dp[k - 1][i][j]) % MOD;
}
}
}
return dp[n][1][1];
}
int main()
{
cin >> n >> p;
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
cin >> a[i][j];
}
}
for (int i = 1; i <= n; i++)
{
cin >> b[i];
}
int result = 0;
for (int i = 0; i < p; i++)
{
for (int j = 0; j < p; j++)
{
result = (result + (1ll << (i + j)) % MOD * get(i, j)) % MOD;
}
}
cout << result << endl;
return 0;
}