2021-07-01 集训题解

国际儿童节

题目传送门

Description

Solution

不难想到,你只需要计算出:

[[FWT]A_i=sum_{j_1,j_2,j_3,...,j_n} [oplus_{h=1}^{n}S_{h,j_h}|i] imes prod_{j=1}^{n} P_{h,j_h} ]

然后 ( exttt{IDWT}) 一下就可以得到答案了。问题就是如何求出这个东西。

可以想到的是,因为 (k) 较小,所以我们可以枚举每种集合,然后打一个标记,之后前缀积一下,不过考虑到存在 (S_2|S_1,S_1|S) 的情况的时候会算重,所以还需要除去子集的影响,但因为有除以 (0) 的情况,所以还需要记录 (0) 的指数。

复杂度 (Theta(sum k_i imes 2^k+2^m imes m))

Code

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

#define Int register int
#define mod 1000000007
#define MAXN 1005

template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

#define MAXM 1<<11
int n,m,lim,s[15],p[15],z[1 << 20],f[1 << 20],lg[MAXM],g1[MAXM],g2[MAXM],siz[MAXM],gS[MAXM],gP[MAXM],inv[MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){
	int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);
	return res;
}
void Add (int &a,int b){a = add (a,b);}
void Sub (int &a,int b){a = dec (a,b);}

int lowbit (int x){return x & (-x);}

void init (){
	for (Int i = 1;i < (1 << 10);++ i) siz[i] = siz[i >> 1] ^ (i & 1);
	for (Int i = 0;i <= 10;++ i) lg[1 << i] = i;
	for (Int i = 1;i <= 1000;++ i) inv[i] = qkpow (i,mod - 2);
}

void makeit (int up){
	z[0] ++;
	for (Int S = 1;S < up;++ S){
		g1[S] = g2[S] = 0;
		gS[S] = gS[S ^ lowbit(S)] | s[lg[lowbit(S)]];
		gP[S] = add (gP[S ^ lowbit(S)],p[lg[lowbit(S)]]);
		if (siz[S]) z[gS[S]] --;else z[gS[S]] ++;
	}
	g1[0] = g2[0] = 1;
	for (Int S = 1;S < up;++ S) g1[S] = gP[S],g2[S] = inv[gP[S]];
	for (Int j = 1;j < up;j <<= 1) for (Int i = 1;i < up;++ i) if (i & j) g1[i] = mul (g1[i],g2[i ^ j]),g2[i] = mul (g2[i],g1[i ^ j]);
	for (Int S = 1;S < up;++ S) f[gS[S]] = mul (f[gS[S]],g1[S]);
}

signed main(){
	freopen ("childhood.in","r",stdin);
	freopen ("childhood.out","w",stdout);
	read (n,m),lim = 1 << m,init ();int iv = 1;
	for (Int i = 0;i < lim;++ i) f[i] = 1;
	for (Int i = 1;i <= n;++ i){
		int k,t = 0;read (k);
		for (Int j = 0;j < k;++ j) read (s[j],p[j]),Add (t,p[j]);
		makeit (1 << k),iv = mul (iv,inv[t]);
	}
	for (Int j = 1;j < lim;j <<= 1) for (Int i = 1;i < lim;++ i) if (i & j) z[i] += z[i ^ j],f[i] = mul (f[i],f[i ^ j]);
	for (Int S = 0;S < lim;++ S) if (z[S]) f[S] = 0;
	for (Int j = 1;j < lim;j <<= 1) for (Int i = 1;i < lim;++ i) if (i & j) Sub (f[i],f[i ^ j]); 
	for (Int i = 0;i < lim;++ i) write (mul (f[i],iv)),putchar (' ');putchar ('
');
	return 0;
}

俄罗斯套娃

题目传送门

Description

Solution

考虑首先第一维按从小到大排序,第二维按从大到小排序。

那么 (i) 可以包含 (j) 当且仅当 (i>j)(r_i>r_j),所以可以不考虑第一维了。

然后我们考虑用线段树维护信息,可以记录下每个线段树上区间 ([l,r]) 的区间最大值,以及只考虑该区间内的最少套娃数。那么你就可以 (log^2n) 解决查询一个区间 ([l,r]) 后面已有最大值 (v) 时的最少套娃数。

考虑如何查询一个区间内一个数值区间内的贡献,你可以按照上限边插点边查询,然后要去掉下限以下的点的话直接把初始已知最大值设为下线就好了。

复杂度 (Theta(nlog^2n))

Code

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

#define Int register int
#define MAXN 1000005

template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

int n,q,ans[MAXN];

struct node{
	int v1,v2;
	bool operator < (const node &p)const{return v1 != p.v1 ? v1 < p.v1 : v2 > p.v2;}
}a[MAXN];

struct que{
	int l,r,vd,ind;
}; 
vector <int> S[MAXN];
vector <que> H[MAXN];

int findit1 (int v){
	int l = 1,r = n,ans = n + 1;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (a[mid].v1 >= v) ans = mid,r = mid - 1;
		else l = mid + 1;
	}
	return ans;
}
int findit2 (int v){
	int l = 1,r = n,ans = 0;
	while (l <= r){
		int mid = (l + r) >> 1;
		if (a[mid].v1 <= v) ans = mid,l = mid + 1;
		else r = mid - 1;
	}
	return ans;
}

struct Segment{
	int mx[MAXN << 2],sum[MAXN << 2];
	int getit (int x,int l,int r,int v){
		if (!mx[x] || mx[x] < v) return 0;
		if (l == r) return 1;
		int mid = (l + r) >> 1;
		if (mx[x << 1 | 1] < v) return getit (x << 1,l,mid,v);
		else return sum[x] - sum[x << 1 | 1] + getit (x << 1 | 1,mid + 1,r,v);
	}
	void pushup (int x,int l,int r){
		int mid = l + r >> 1;
		mx[x] = max (mx[x << 1],mx[x << 1 | 1]);
		sum[x] = sum[x << 1 | 1] + getit (x << 1,l,mid,mx[x << 1 | 1]);
	}
	void modify (int x,int l,int r,int pos){
		if (l == r) return mx[x] = a[l].v2,sum[x] = 1,void ();
		int mid = (l + r) >> 1;
		if (pos <= mid) modify (x << 1,l,mid,pos);
		else modify (x << 1 | 1,mid + 1,r,pos);
		pushup (x,l,r);
	}
	int query (int x,int l,int r,int ql,int qr,int &v){
		if (!mx[x] || mx[x] < v) return 0;
		if (l >= ql && r <= qr){
			int tmp = getit (x,l,r,v);
			chkmax (v,mx[x]);return tmp;
		}
		int mid = (l + r) >> 1,res = 0;
		if (qr > mid) res += query (x << 1 | 1,mid + 1,r,ql,qr,v);
		if (ql <= mid) res += query (x << 1,l,mid,ql,qr,v);
		return res;
	}
}Tree;

signed main(){
    freopen ("baby.in","r",stdin);
    freopen ("baby.out","w",stdout);
	read (n,q);
	for (Int i = 1;i <= n;++ i) read (a[i].v1);
	for (Int i = 1;i <= n;++ i) read (a[i].v2);
	sort (a + 1,a + n + 1);
	for (Int i = 1;i <= n;++ i) S[a[i].v2].push_back (i);
	for (Int i = 1;i <= q;++ i){
		int v1u,v1d,v2u,v2d;read (v1u,v2u,v1d,v2d);
		int l = findit1 (v1d),r = findit2 (v1u);
		if (l <= r) H[v2u].push_back (que{l,r,v2d,i}); 
	}
	for (Int v = 1;v <= n;++ v){
		for (Int x : S[v]) Tree.modify (1,1,n,x);
		for (que x : H[v]) ans[x.ind] = Tree.query (1,1,n,x.l,x.r,x.vd);   
	}
	for (Int i = 1;i <= q;++ i) write (ans[i]),putchar ('
');
	return 0;
}

最小点覆盖

题目传送门

Description

Solution

Code

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

#define Int register int
#define MAXN 3005

template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

int f[15][MAXN][MAXN];
int lowbit (int x){return x & (-x);}
int C (int n,int m){return (n & m) == m;}
int getit (int d,int n,int m){
	if (m < 0) return 0;
	if (m == 0) return 1;
	if ((1 << d) > n) return m != n && m == lowbit (n);
	if (f[d][n][m]) return f[d][n][m] ^ 1;
	int &res = f[d][n][m] = 1;
	for (Int i = 0;i < (n >> d);++ i)
		if (C (i + (((n >> d) - i - 1) >> 1),i)) res ^= getit (d + 1,n - (1 << d) * i,m - (1 << d) * i);
	return res ^ 1;
}

signed main(){
	freopen ("cover.in","r",stdin);
	freopen ("cover.out","w",stdout);
	int T;read (T);
	while (T --> 0){
		int n,m;read (n,m);
		write (getit (0,n,m)),putchar ('
');
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Dark-Romance/p/14961167.html