#4713. 方程

題目描述

題解

考慮最高位 kk ,如果 mim_ikk 位爲 11 ,且 xix_ikk 位爲 00 的話,那其他的 xx 可以取任意值,因爲 xix_i 可以取到 [0,2k)[0,2^k) 的任意一個數,所以可以調整一下,據此我們可以列出dp: fi,jf_{i,j} 表示前 ii 個數,有 jj 個數第 kk 位爲 11 ,可以得到方程的解的組數,那如果 mim_i11 的話可以列出轉移式子 fi,j=fi1,j×2k+fi1,j1×(mi2k+1)f_{i,j}=f_{i-1,j} \times 2^k+f_{i-1,j-1} \times (m_i-2^k+1) ,最後要記得除以 2k2^k 因爲其他數確定了,這個數也就確定了,所以只有 ×1\times 1 的貢獻,然後繼續遞歸即可

效率: O(30Tn2)O(30Tn^2)

代碼

#include <bits/stdc++.h>
using namespace std;
const int P=1e9+7;
int n,m,a[55],f[55][55],w[55];
int solve(int x){
	if (x<0) return 1;
	f[0][0]=1;int u=0,v=0;
	for (int i=1;i<=n;i++)
		if (a[i]&(1<<x)){
			u++;f[u][0]=1ll*f[u-1][0]*(1<<x)%P;
			for (int j=1;j<=u;j++)
				(f[u][j]+=(1ll*f[u-1][j]*(1<<x)%P+1ll*f[u-1][j-1]*((a[i]&((1<<x)-1))+1)%P)%P)%=P;
		}
		else for (int j=0;j<=u;j++) f[u][j]=1ll*f[u][j]*((a[i]&((1<<x)-1))+1)%P;
	for (int i=0;i<u;i++)
		if ((i&1)==((m>>x)&1))
			(v+=1ll*f[u][i]*w[x]%P)%=P;
	for (int i=0;i<=u;i++)
		for (int j=0;j<=u;j++) f[i][j]=0;
	if ((u&1)==((m>>x)&1))
		return (v+solve(x-1))%P;
	return v;
}
int main(){
	w[0]=1;w[1]=(P+1)>>1;
	for (int i=2;i<55;i++)
		w[i]=1ll*w[i-1]*w[1]%P;
	while(~scanf("%d%d",&n,&m)){
		for (int i=1;i<=n;i++)
			scanf("%d",&a[i]);
		printf("%d\n",solve(30));
	}
	return 0;
}
發佈了161 篇原創文章 · 獲贊 5 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章