【bzoj3866】The Romantic Hero dp

题目描述

给你n个数,从中选出两个不相交非空集合S和T,使得S中的每一个元素都在T集合的前面,并且S集合中的所有数的亦或等于T集合中的所有数的与,求方案数 mod 10^9+7。

输入

The first line contains an integer T, denoting the number of the test cases.
For each test case, the first line contains a integers n.
The next line contains n integers a_1,a_2,...,a_n which are separated by a single space.
n<=10^3, 0 <= a_i <1024, T<=20.

输出

For each test case, output the result in one line.

样例输入

2
3
1 2 3
4
1 2 3 3

样例输出

1
4


题解

dp

设$s[i][j]$表示前$i$个数选$i$,选出的数的亦或为$j$的方案数,那么直接使用前缀和优化,转移时枚举之前的$j$,与当前位置计算得出新的$j$即可。

设$t[i][j]$表示从$i$到$n$选$i$,选出的数的与为$j$的方案数,那么转移同理。

最后枚举$S$/$T$集合的第一个数,使用乘法原理计算即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define m 1024
#define mod 1000000007
using namespace std;
int a[m] , fs[m][m] , ss[m][m] , ft[m][m] , st[m][m];
int main()
{
	int T;
	scanf("%d" , &T);
	while(T -- )
	{
		int n , i , j , ans = 0;
		scanf("%d" , &n);
		for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
		memset(fs , 0 , sizeof(fs)) , memset(ss , 0 , sizeof(ss));
		memset(ft , 0 , sizeof(ft)) , memset(st , 0 , sizeof(st));
		ss[0][0] = st[n + 1][m - 1] = 1;
		for(i = 1 ; i <= n ; i ++ )
		{
			for(j = 0 ; j < m ; j ++ ) fs[i][j ^ a[i]] = (fs[i][j ^ a[i]] + ss[i - 1][j]) % mod;
			for(j = 0 ; j < m ; j ++ ) ss[i][j] = (ss[i - 1][j] + fs[i][j]) % mod;
		}
		for(i = n ; i ; i -- )
		{
			for(j = 0 ; j < m ; j ++ ) ft[i][j & a[i]] = (ft[i][j & a[i]] + st[i + 1][j]) % mod;
			for(j = 0 ; j < m ; j ++ ) st[i][j] = (st[i + 1][j] + ft[i][j]) % mod;
		}
		for(i = 1 ; i < n ; i ++ )
		{
			ss[i][0] -- ;
			for(j = 0 ; j < m ; j ++ ) ans = (ans + (long long)ss[i][j] * ft[i + 1][j]) % mod;
		}
		printf("%d
" , ans);
	}
	return 0;
}

 

原文地址:https://www.cnblogs.com/GXZlegend/p/7509841.html