codeforces contest 1119

CF 1119 A

题目大意:给一个数组 a i a_i ai,求最大的 i − j i-j ij使得 a i ≠ a j a_i\neq a_j ai̸=aj,输出这个 i − j i-j ij的值
题解: 这题可以做到 O ( n ) \mathcal O(n) O(n),有一个很好的性质,就是一定满足 i = n i=n i=n j = 1 j=1 j=1。我们发现这很好证明,如果 a 1 ≠ a n a_1\neq a_n a1̸=an,那么答案就是 n − 1 n-1 n1了,否则我们发现数组的一个前缀以及一个后缀分别是若干个与 a 1 a_1 a1相等的值,我们发现去掉这两个前后缀之后的内部的答案严格小于端点在前后缀之中的,而端点在前后缀之中的情况我们发现端点一定有 1 1 1 n n n

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
int n,a[300001],ans;
int main()
{
	read(n);
	for(rg int i=1;i<=n;i++)read(a[i]);
	for(rg int i=1;i<=n;i++)if(a[i]!=a[1])ans=max(ans,i-1);
	for(rg int i=1;i<=n;i++)if(a[i]!=a[n])ans=max(ans,n-i);
	print(ans);
	return 0;
}

CF 1119 B

题目大意:现在有个 H ∗ 2 H*2 H2的立体冰箱,可以在任何一个格子顶部放隔板,现在有一些牛奶盒按顺序放入冰箱(牛奶盒不能叠起来,只能放在隔板上),第 i i i个牛奶盒为 a i ∗ 1 a_i*1 ai1的长方形,问最多能放几个牛奶盒
题解: 容易发现这题显然可二分,二分完之后直接贪心放判定即可,复杂度 O ( n l o g 2 n ) \mathcal O(nlog^2n) O(nlog2n)

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
int n,H,a[300001],b[300001],l,r,ans;
bool check(const int mid)
{
	for(rg int i=1;i<=mid;i++)b[i]=a[i];
	std::sort(b+1,b+mid+1);
	int cost=0;
	for(rg int i=mid;i>=0;i-=2)
	{
		cost+=b[i];
		if(cost>H)return 0;
	}
	return 1;
}
int main()
{
	read(n),read(H),l=1,r=n;
	for(rg int i=1;i<=n;i++)read(a[i]);
	while(l<=r)
	{
		const int mid=(l+r)>>1;
		if(check(mid))ans=mid,l=mid+1;
		else r=mid-1;
	}
	print(ans);
	return 0;
}

CF 1119 C

题目大意:给一个 n ∗ m n*m nm的01矩阵,每次可以选定一个子矩阵并且对子矩阵的四个角异或1,求是否能将整个矩阵异或成0
题解: 我们发现,这个操作进行前缀异或操作后相当于是对一个数组进行矩形异或操作(但是范围有限制,只能1~n-1行的1~m-1列),那么将给出的矩形进行前缀异或操作后看是否有范围外的1即可
复杂度 O ( n m ) \mathcal O(nm) O(nm)

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
int n,m,a[501][501],fla=1;
int main()
{
	read(n),read(m);
	for(rg int i=1;i<=n;i++)
		for(rg int j=1;j<=m;j++)
			read(a[i][j]);
	for(rg int i=1;i<=n;i++)
		for(rg int j=1;j<=m;j++)
		{
			int x;read(x);
			a[i][j]^=x^a[i-1][j]^a[i][j-1]^a[i-1][j-1];
		}
	for(rg int i=1;i<=n;i++)if(a[i][m])fla=0;
	for(rg int i=1;i<=m;i++)if(a[n][i])fla=0;
	if(fla)puts("Yes");
	else puts("No");
	return 0;
}

CF 1119 D

题目大意:现在有一个 n ∗ ∞ n*\infty n的二维整数数组 a i , j a_{i,j} ai,j且满足 a i , j = s i + j a_{i,j}=s_i+j ai,j=si+j,给定一些询问,问 l i l_i li列到 r i r_i ri列有多少种不同的整数
(数据范围 n , q ≤ 100000 n,q\le100000 n,q100000
题解: 我们发现 l i l_i li r i r_i ri的值并不重要,有用的只有 r i − l i r_i-l_i rili的值,我们发现本题就变成了线段长度并,我们发现数轴上的线段段数会随着 r i − l i r_i-l_i rili的变大而减少,我们可以预处理每个段数时覆盖的长度,那么 r i − l i r_i-l_i rili更大但不足以接上下一段线段时就会给每条线段带来延伸,直接乘起来即可,复杂度 O ( n l o g n ) \mathcal O(nlogn) O(nlogn)(此处 n , q n,q n,q同阶)

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
int n,q;
ll s[100001],c[100002],ans[100001],las=-1,dq=0,before;
int main()
{
	read(n);
	for(rg int i=1;i<=n;i++)read(s[i]);
	std::sort(s+1,s+n+1);
	n=std::unique(s+1,s+n+1)-s-1;
	ans[1]=n;
	for(rg int i=2;i<=n;i++)c[i]=s[i]-s[i-1];
	std::sort(c+1,c+n+1);
	c[n+1]=2000000000000000000ll;
	for(rg int i=2;i<=n+1;i++)
		if(c[i]!=dq)
		{
			ans[i-1]=ans[i-2]+(dq-las-1)*before+n-i+2;
			before=n-i+2; 
			las=dq,dq=c[i];
		}
		else ans[i-1]=ans[i-2];
	read(q);
	for(rg int i=1;i<=q;i++)
	{
		ll x,y;read(x),read(y),y-=x;
		x=std::upper_bound(c+1,c+n+1,y)-c-1;
		print(ans[x]+(y-c[x])*(n-x+1)),putchar(' ');
	}
	return 0;
}

CF 1119 E

题目大意:长度为 2 i 2^i 2i的棍子有 a i a_i ai根,问最多能组成多少个三角形
题解: 首先有个显然的结论,本题的三角形三边长只有两种情况: A = B = C A=B=C A=B=C或者 A &lt; B = C A&lt;B=C A<B=C,我们发现由于边长限制,其它组合都不符合两边之和大于第三边的限制。进行整合,我们发现就是 A ≤ B = C A\le B=C AB=C。接下来进行贪心即可

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
ll n,a[300001],all,usd,ans;
int main()
{
	read(n);
	for(rg int i=0;i<n;i++)read(a[i]),all+=a[i];
	for(rg int i=n-1;i>=0;i--)
	{
		int A=min(all-usd,a[i]),other=a[i]-A;
		if((all-usd-A)*2<=A)
		{
			ll add=all-usd-A;
			usd+=add,A-=add*2,ans+=add;
			add=A/3;
			A-=add*3,ans+=add;
			usd=max(usd-A,0ll);
		}
		else
		{
			ll add=A/2;
			usd+=add,A-=add*2,ans+=add;
			usd=max(usd-A,0ll);
		}
		usd=max(usd-other,0ll),all-=a[i];
	}
	print(ans);
	return 0;
}

CF 1119 F

题目大意:有一棵 n n n个节点的树,边有边权,现在要求你删权值和尽量小边,使得每个点的度数小于等于 x x x,对于每个 x x x输出答案
题解:(此处感谢fcwww同学的帮忙)
首先有个很好的性质,就是
∑ i = 1 n ∑ u = 1 n [ d u ≥ i ] = ∑ u = 1 n d u = 2 ( n − 1 ) \sum_{i=1}^n\sum_{u=1}^n[d_u\ge i]=\sum_{u=1}^nd_u=2(n-1) i=1nu=1n[dui]=u=1ndu=2(n1)
意思是说,对于一个 x x x,直接枚举度数大于 x x x的节点的复杂度是可以接受的
考虑现在相当于是一个森林,对每棵树进行树形dp
f i , 0 f_{i,0} fi,0代表 i i i子树内解决, i i i节点到父亲的边不被选择的最小花费
f i , 1 f_{i,1} fi,1代表 i i i子树内解决, i i i节点到父亲的边被选择的最小花费
考虑树上的一个儿子,若其度数 ≤ x \le x x,那么花费就是边的边权 w w w,否则花费是 f i , 1 − f i , 0 + w f_{i,1}-f_{i,0}+w fi,1fi,0+w
每个点维护所有到不满足条件的儿子的边的长度set
从小到大枚举 x x x,点逐渐的不满足条件,这样的话那个set就是不断的加元素
我们考虑如何计算出dp值,我们发现满足条件的儿子会往set里加元素
我们不要取最小的那些元素,而是把大的元素删掉,这样就保证了复杂度为 O ( n l o g n ) \mathcal O(nlogn) O(nlogn)
另外实现的时候要注意细节,否则很容易写挂复杂度

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
const int maxn=250001,maxm=500001;
int n,head[maxn],nxt[maxm],tow[maxm],vau[maxm],tmp,d[maxn];
inline void addb(const int u,const int v,const int w)
{
	tmp++;
	nxt[tmp]=head[u];
	head[u]=tmp;
	tow[tmp]=v;
	vau[tmp]=w;
}
std::vector<int>T[maxn];
int fa[maxn],nex[maxn+1],las;
void ffa(const int u)
{
	for(rg int i=head[u];i;i=nxt[i])
	{
		const int v=tow[i];
		if(v!=fa[u])fa[v]=u,ffa(v);
	}
}
bool vis[maxn];
struct SET
{
	std::multiset<int,std::greater<int> >main;
	std::vector<int>erased,added;
	ll lj;int tot;
	void insert(const int x){main.insert(x),lj+=x,tot++;}
	void resize(const int x)
	{
		while(tot>x)
		{
			tot--,lj-=*main.begin();
			main.erase(main.begin());
		}
	}
	void RESIZE(const int x)
	{
		while(tot>x)
		{
			tot--,lj-=*main.begin(),erased.push_back(*main.begin());
			main.erase(main.begin());
		}
	}
	void INSERT(const int x)
	{
		main.insert(x),lj+=x,tot++;
		added.push_back(x);
	}
	void BACK()
	{
		for(std::vector<int>::iterator Pos=erased.begin();Pos!=erased.end();Pos++)main.insert(*Pos),tot++,lj+=*Pos;
		erased.clear();
		for(std::vector<int>::iterator Pos=added.begin();Pos!=added.end();Pos++)main.erase(main.find(*Pos)),tot--,lj-=*Pos;
		added.clear();
	}
}s[maxn];
ll f[maxn][2];
int G;
void dfs(const int u)
{
	int ned=d[u]-G;
	s[u].resize(ned);
	ll tot=0;
	int *lc=&head[u];
	for(rg int i=head[u];i;i=nxt[i])
	{
		const int v=tow[i];
		if(vis[v])
		{
			(*lc)=nxt[i];
			continue;
		}
		else lc=&nxt[i];
		if(v!=fa[u])
		{
			dfs(v);
			if(f[v][1]+vau[i]<=f[v][0])ned--,tot+=f[v][1]+vau[i];
			else
			{
				tot+=f[v][0];
				s[u].INSERT(f[v][1]+vau[i]-f[v][0]);
			}
		}
	}
	s[u].RESIZE(max(ned,0));
	f[u][0]=s[u].lj+tot;
	ned--;
	s[u].RESIZE(max(ned,0));
	f[u][1]=s[u].lj+tot;
	s[u].BACK();
}
int main()
{
	read(n);
	for(rg int i=1;i<n;i++)
	{
		int u,v,w;read(u),read(v),read(w);
		addb(u,v,w),addb(v,u,w),d[u]++,d[v]++;
	}
	for(rg int i=1;i<=n;i++)T[d[i]].push_back(i);
	for(rg int i=n;i>=1;i--)
	{
		nex[i]=las;
		if(!T[i].empty())las=i;
	}
	vis[0]=1;
	ffa(1);
	for(rg int i=1;i<=n;i++)
	{
		G=i-1;
		ll ans=0;
		for(rg int p=i;p;p=nex[p])
		{
			for(std::vector<int>::iterator Pos=T[p].begin();Pos!=T[p].end();Pos++)
				if(vis[fa[*Pos]])
				{
					dfs(*Pos);
					ans+=f[*Pos][0];
				}
		}
		print(ans),putchar('\n');
		for(std::vector<int>::iterator Pos=T[i].begin();Pos!=T[i].end();Pos++)
		{
			const int u=*Pos;
			vis[u]=1;
			for(rg int j=head[u];j;j=nxt[j])
			{
				const int v=tow[j];
				if(!vis[v])s[v].insert(vau[j]);
			}
		}
	}
	return 0;
}

CF 1119 G

题目大意:现在有 m m m个敌人,第 i i i个敌人的血量为 b i b_i bi,现在你要设计出炸弹的分组方式,使得一组炸弹的第 i i i个大小为 a i a_i ai,并且 ∑ a i = n \sum a_i=n ai=n
每次给你一组炸弹,你可以将每个炸弹分别扔向某个敌人,你希望用最少的组数炸完所有敌人,问组数与炸弹分配方式、炸法
题解: 我们发现,我们可以按顺序炸敌人,按顺序将敌人每次炸 n n n,炸到血量低于 n n n,假设此时其血量为 k i k_i ki,这个时候假设可以组合出当前它的血量,然后剩下的炸药炸下个即可,容易发现这样的答案一定是最优的,即 ⌈ ∑ k i n ⌉ \left\lceil\frac{\sum k_i}{n}\right\rceil nki
至于如何构造出炸药分配方式,我们发现只需要把所有 k k k排序后取 k i − k i − 1 k_i-k_{i-1} kiki1即可
在本题中的 k k k可能会有特殊情况,比如炸下个人下个人就直接死了,我们发现没关系,只需要将下个人的 k k k加上之前用过的炸药量即可

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
template <typename T> inline T gcd(const T a,const T b){if(!b)return a;return gcd(b,a%b);}
template <typename T> inline void maxd(T&a,const T b){a=a>b?a:b;}
template <typename T> inline T abs(const T a){return a>0?a:-a;}
int n,m,a[1000001],b[1000001],k[1000001],all,pl[1000001];
int main()
{
	read(n),read(m);
	for(rg int i=1;i<=m;i++)read(a[i]),b[i]=a[i],all+=a[i];
	for(rg int i=1;i<=m;i++)
	{
		k[i]=a[i]%n;
		if(k[i])
		{
			int las=n-k[i];
			for(int j=i+1;j<=m+1;j++)
				if(a[j]<las&&j!=m+1)
				{
					k[j]=k[j-1]+a[j];
					las-=a[j];
				}
				else
				{
					i=j-1;
					a[j]-=las;
					break;
				}
		}
	}
	std::sort(k+1,k+m);
	print((all+n-1)/n),putchar('\n');
	k[m]=n;
	for(rg int i=1;i<=m;i++)print(k[i]-k[i-1]),putchar(' '),pl[k[i]]=i;putchar('\n');
	for(rg int i=1;i<=m;i++)a[i]=b[i];
	for(rg int i=1;i<=m;i++)
	{
		while(a[i]>=n)
		{
			a[i]-=n;
			for(rg int j=1;j<=m;j++)print(i),putchar(' ');putchar('\n');
		}
		k[i]=a[i];
		if(k[i]>0&&i==m)
		{
			for(rg int j=1;j<=m;j++)print(i),putchar(' ');putchar('\n');
		}
		else if(k[i]>0)
		{
			int las=n-k[i],zq=0;
			while(zq<pl[k[i]])zq++,print(i),putchar(' ');
			for(int j=i+1;j<=m;j++)
				if(j==m)
				{
					i=j-1;
					a[j]-=las;
					while(zq<m)zq++,print(j),putchar(' ');
					break;
				}
				else if(a[j]<las)
				{
					k[j]=k[j-1]+a[j];
					las-=a[j];
					while(zq<pl[k[j]])zq++,print(j),putchar(' ');
				}
				else
				{
					i=j-1;
					a[j]-=las;
					while(zq<m)zq++,print(j),putchar(' ');
					break;
				}
			putchar('\n');
		}
	}
	return 0;
}

CF 1119 H

题目大意:现在有n个数组,第 i i i个数组有 x x x a i a_i ai y y y b i b_i bi, z z z c i c_i ci,对于每个 v ∈ [ 0 , 2 k ) v\in [0,2^k) v[0,2k),求在每个数组中选一个数异或起来的结果等于 v v v的方案数
x , y , z ≤ 1 0 9 , n ≤ 1 0 5 , k ≤ 17 x,y,z\le10^9,n\le10^5,k\le17 x,y,z109,n105,k17
题解: 首先我们先考虑暴力,直接FWT是 O ( n 2 k k ) \mathcal O(n2^kk) O(n2kk)的,显然不能通过
我们思考更优的做法,首先我们发现,我们可以将 ( a i , b i , c i ) (a_i,b_i,c_i) (ai,bi,ci)改为 ( 0 , a i   x o r   b i , a i   x o r   c i ) (0,a_i\ xor\ b_i,a_i\ xor\ c_i) (0,ai xor bi,ai xor ci),之后我们将表述成 A i = 0 , B i = a i   x o r   b i , C i = a i   x o r   c i A_i=0,B_i=a_i\ xor\ b_i,C_i=a_i\ xor\ c_i Ai=0Bi=ai xor biCi=ai xor ci
考虑暴力时FWT的结果,对数组进行FWT后,数组中将只有4种值:x+y+z,x+y-z,x-y+z,x-y-z(根据FWT的定义容易发现,x的位置由于一开始是0,所以FWT后的贡献一定都是正的)
如果我们的快速的算出某个位置上一个数出现了几次,那么我们就可以快速的进行FWT,然后这样的话进行一遍IFWT就好了
对于每个位置,我们设四个值分别出现了 i , j , k , l i,j,k,l i,j,k,l次,容易发现 i + j + k + l = n i+j+k+l=n i+j+k+l=n
我们需要找到更多等式来解出 i , j , k , l i,j,k,l i,j,k,l
我们发现只要把所有 B i B_i Bi加到一起进行FWT,就可以得出 i + j − k − l = v a l u e   o f   p o s i t i o n i+j-k-l=value\ of\ position i+jkl=value of position
把所有 C i C_i Ci加到一起进行FWT,就可以得出 i − j + k − l = v a l u e   o f   p o s i t i o n i-j+k-l=value\ of\ position ij+kl=value of position
把所有 B i x o r C i B_ixorC_i BixorCi加到一起进行FWT,就可以得出 i − j − k + l = v a l u e   o f   p o s i t i o n i-j-k+l=value\ of\ position ijk+l=value of position
这样我们就可以通过3次FWT来算出所有的 i , j , k , l i,j,k,l i,j,k,l,然后一次FWT算出答案即可
复杂度 O ( 2 k k + n l o g n ) \mathcal O(2^kk+nlogn) O(2kk+nlogn)
要注意前3遍FWT是不需要取模的,并且要开到longlong

#include<bits/stdc++.h>
typedef long long ll;
#define rg register
template <typename T> inline void read(T&x){char cu=getchar();x=0;bool fla=0;while(!isdigit(cu)){if(cu=='-')fla=1;cu=getchar();}while(isdigit(cu))x=x*10+cu-'0',cu=getchar();if(fla)x=-x;}
template <typename T> inline void printe(const T x){if(x>=10)printe(x/10);putchar(x%10+'0');}
template <typename T> inline void print(const T x){if(x<0)putchar('-'),printe(-x);else printe(x);}
template <typename T> inline T min(const T a,const T b){return a<b?a:b;}
template <typename T> inline T max(const T a,const T b){return a>b?a:b;}
const int mod=998244353,inv2=(mod+1)>>1,maxn=131072;
int Md(const int x){return x>=mod?x-mod:x;}
ll pow(ll x,ll y)
{
	ll res=1;x=(x+mod+mod)%mod;
	for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;
	return res;
}
int n,k,lenth;
inline void FWT(ll*A)
{
    for(rg int i=1;i<lenth;i<<=1)
        for(rg int j=0;j<lenth;j+=(i<<1))
            for(rg int k=0;k<i;k++)
            {
                const int x=A[j+k],y=A[j+k+i];
                A[j+k]=(x+y),A[j+k+i]=(x-y);
            }
}
inline void FWT(ll*A,const int fla)
{
    for(rg int i=1;i<lenth;i<<=1)
        for(rg int j=0;j<lenth;j+=(i<<1))
            for(rg int k=0;k<i;k++)
            {
                const int x=A[j+k],y=A[j+k+i];
                A[j+k]=Md(x+y),A[j+k+i]=Md(x+mod-y);
            }
    if(fla==-1)
    {
		const int inv=pow(inv2,(ll)k);
		for(rg int i=0;i<lenth;i++)A[i]=(ll)A[i]*inv%mod;
    } 
}
ll A[maxn],B[maxn],C[maxn],x,y,z,v;
int main()
{
	read(n),read(k),read(x),read(y),read(z),lenth=1<<k;
	for(rg int i=1;i<=n;i++)
	{
		int a,b,c;read(a),read(b),read(c);v^=a,b^=a,c^=a,a=b^c;
		A[b]++,B[c]++,C[a]++;
	}
	FWT(A),FWT(B),FWT(C);
	for(rg int p=0;p<lenth;p++)
	{
		const ll a=n,b=A[p],c=B[p],d=C[p];
		A[p]=pow(x+y+z,(a+b+c+d)/4)
		*pow(x+y-z,(a+b-c-d)/4)%mod
		*pow(x-y+z,(a-b+c-d)/4)%mod
		*pow(x-y-z,(a-b-c+d)/4)%mod;
	}
	FWT(A,-1);
	for(rg int i=0;i<lenth;i++)print(A[i^v]),putchar(' ');
	return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值