Loading

[题解] 序列(sequence)

题目大意

给定一个长度为 \(N\)​ 的非负整数序列 \(A_1,A_2, \ldots ,A_N\)​,和一个正整数 \(M\)​。序列 \(A\) ​满足 \(\forall 1 \le i \le N, A_i \in [0, 2^M)\)​。定义一个长度为 \(N\) ​的非负整数序列 \(B\) ​是合法的,当且仅当其满足如下三个条件:

(1)\(\forall 1 \le i \le N\)​, \(B_i \in [0,2^M)\)​;

(2)\(\forall 1\le i< N,(A_i\ \text{and}\ B_i )\ \le (A_{i+1}\ \text{and}\ B_{i+1})\),这里的 \(\text{and}\) 表示二进制按位与;

(3)\(\forall 1 \le i < N, (A_i\ \text{or}\ B_i ) \ge (A_{i+1}\ \text{or}\ B_{i+1})\),这里的 \(\text{or}\) ​表示二进制按位或。

请你求出,有多少个满足条件的序列 \(B\)​。由于答案可能很大,你只需要输出其在模 \(10^9+7\) ​意义下的结果。

数据范围:$1 \le M \le 30,1 \le N\le 100,\forall 1 \le i \le N, A_i \in [0,2^M) $。

时间限制:2000ms

空间限制:1024MB

解题思路

首先要有判断从哪个角度入手问题比较可做的能力,可以发现如果想要从 \(B\) 数组入手不太容易,于是考虑从对应的角度去考虑。

boshi:一一对应。

\(A\text{ or }B\) 记作 \(C\)\(A\text{ and }B\) 记作 \(D\),不难发现一组合法的 \((C,D)\) 即对应一个满足条件的 \(B\) 序列。而 \(C\)\(D\) 相互独立,于是考虑分别计数。

又由于是位运算相关,故按位考虑,设 \(f_{b,l,r}\) 表示从高到低考虑到第 \(b\) 位,\([l,r]\) 间的数字还是相同的,然后按照下一位枚举断点转移即可。

#include <bits/stdc++.h>
using namespace std;

const int N(105), M(30), mod(1e9 + 7);

int n, m, a[N];
int f[M][N][N];

inline void read(int &x){
	x = 0; int f = 1, c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)) x = x * 10 + c - 48, c = getchar();
	x *= f;
}

inline void MOD(int &x){ x = x + ((x >> 31) & mod); }

inline void init(){ memset(f, -1, sizeof(f)); }
int dfs(int b, int l, int r, int op){
	if(b == -1) return 1; if(l > r) return 1;
	if(~f[b][l][r]) return f[b][l][r];
	f[b][l][r] = 0;
	int L = r; while(l <= L && ((a[L] >> b) & 1) == op) --L;
	for(int i(L); i <= r; ++i)
		MOD(f[b][l][r] += 1LL * dfs(b - 1, l, i, op) * dfs(b - 1, i + 1, r, op) % mod - mod);
	return f[b][l][r];
}

int main(){
	freopen("sequence.in", "r", stdin);
	freopen("sequence.out", "w", stdout);
	read(n), read(m);
	for(int i(1); i <= n; ++i) read(a[i]);
	int And, Or, ans;
	init(), And = dfs(m - 1, 1, n, 1);
	init(), Or = dfs(m - 1, 1, n, 0);
	ans = 1LL * And * Or % mod;
	printf("%d\n", ans);
	return 0;
}
posted @ 2021-09-17 21:11  IrisT  阅读(507)  评论(0编辑  收藏  举报