8.21 T2 矩阵补全(FWT)

http://cplusoj.com/d/senior/p/NODSX2302B

考虑 b i ∈ { 1 } b_i\in\{1\} bi{1} 怎么做,这是个裸的FWT,FWT后弄个快速幂就行

如果 b i ∈ { 0 , 1 } b_i\in\{0,1\} bi{0,1},在0的位我们就要保持原样不能动

b i ∈ { 0 , 1 , 2 , 3 } b_i\in\{0,1,2,3\} bi{0,1,2,3},同理,在对应的位置上我们实行对应的操作。也就是把FWT的每一层弄成 b b b 指定的操作即可。

#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
 #define debag(...) fprintf(stderr, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
 #define debag(...) void(0)
#endif
#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
#define mo (int)(1e9 + 7)
#define N 2000010
int pw(int a, int b) {
	int ans = 1; 
	while(b) {
		if(b & 1) ans *= a; 
		a *= a; b >>= 1; 
		ans %= mo; a %= mo; 
	}
	return ans; 
}
const int inv2 = pw(2, mo-2); 
int n, m, i, j, k, T;
int A[N], a[N], b[N], o, P, l; 
char str[N]; 

void cp() {
	for(i = 0; i < n; ++i) a[i] = A[i]; 
}

void FWT(int *f, int x) {
	for(k = 1, o = 2, l = 0; o <= n; o <<= 1, k <<= 1, ++l) {
		if(b[l] == 1) {
			for(i = 0; i < n; i += o)
				for(j = 0; j < k; ++j)
					f[i + j + k] = (f[i + j + k] + f[i + j] * x) % mo; 
		}
		if(b[l] == 2) {
			for(i = 0; i < n; i += o)
				for(j = 0; j < k; ++j)
					f[i + j] = (f[i + j] + f[i + j + k] * x) % mo; 
		}
		if(b[l] == 3) {
			for(i = 0; i < n; i += o)
				for(j = 0; j < k; ++j) {
					int y = (x == 1 ? 1 : inv2); 
					f[i + j] += f[i + j+ k]; 
					f[i + j + k] = f[i + j] - 2 * f[i + j + k]; 
					f[i + j] = f[i + j] * y % mo; 
					f[i + j + k] = f[i + j + k] * y % mo; 
				}
		}
	}
	debug("l : %lld\n", l); 
	assert(l == m); 
}

void mul() {
	for(i = 0; i < n; ++i) a[i] = pw(a[i], P); 
}

signed main()
{
	#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
//	srand(time(NULL));
//	T=read();
//	while(T--) {
//
//	}
	P = read(); m = read(); n = (1 << m); 
	scanf("%s", str); 
	for(i = 0; i < n; ++i) A[i] = str[i] - '0'; 
	for(i = 0; i < m; ++i) b[i] = read(); 
	for(i = 0; i < n; ++i) debug("%lld ", A[i]); debug("\n"); 
	cp(); FWT(a, 1); 
	for(i = 0; i < n; ++i) debug("%lld ", a[i]); debug("\n"); 
	mul(); FWT(a, -1); 
	int q = read(); 
	while(q--) {
		int x = read(); 
		printf("%lld\n", (a[x] % mo + mo) % mo); 
	}
	return 0;
}



  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值