Live2D

2022/02/08 模拟赛题解

蚌埠住了,挂了 \(75\%\) 的分。

T1

Description

给出一个序列,分成若干段,把每段最大值取出来作为 \(B_{1,2,...,n}\),使 \(\sum_{i=2} ((B_i-B_{i-1})^2+C)\) 最大。

\(n\le 10^6\)

Solution

考试的时候傻了,写了一个线段树套李超树,结果自己乱改没测大样例交上去挂完了。/kk

不难发现,假如对于一个点它能作为最大值的最大区间为 \([\text{col}_i,\text{cor}_i]\),那么我们可以设 \(f_i\) 表示前面 \(i\) 个考虑选了 \(i\) 的最大值,那么我们存在转移式:

\[f_i=\max(f_j+(a_i-a_j)^2+C),\text{cor_j}\ge \text{col_i}-1 \]

至此,我们就可以线段树套李超树做到 \(\Theta(n\log^2n)\) 。不过我们发现我们其实可以去掉限制条件,因为如果中间有更大值一定加入这个更优。所以可以直接李超树 \(\Theta(n\log n)\)

Code

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

#define Int register int
#define ll long long
#define MAXM 1000005

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

ll C,f[MAXM];
int sqr (int x){return x * x;}
int n,a[MAXM],col[MAXM],cor[MAXM];

int cnt,rt,tmp[MAXM];
struct LiChao{
#define ls(x) son[x][0]
#define rs(x) son[x][1]
	int cnt,son[15000005][2];ll tk[15000005],tb[15000005];
	void modify (int &x,int l,int r,ll k,ll b){//表示在[l,r]中插入kx+b这条线段
		if (!x) x = ++ cnt;
		int mid = l + r >> 1;ll vnow = tmp[mid] * k + b,vlst = tmp[mid] * tk[x] + tb[x];
		if (!tk[x]){tk[x] = k,tb[x] = b;return ;}
		if (l == r){
			if (vnow > vlst) tk[x] = k,tb[x] = b;
			return ;
		}
		if (k < tk[x]){
			if (vnow < vlst) modify (ls(x),l,mid,k,b);
			else modify (rs(x),mid + 1,r,tk[x],tb[x]),tk[x] = k,tb[x] = b;
		}
		else{
			if (vnow < vlst) modify (rs(x),mid + 1,r,k,b);
			else modify (ls(x),l,mid,tk[x],tb[x]),tk[x] = k,tb[x] = b;
		}
	}
	ll query (int x,int l,int r,int t){
		if (!tk[x]) return -2e18;
		ll now = tk[x] * tmp[t] + tb[x],mid = l + r >> 1;
		if (t <= mid) chkmax (now,query (ls(x),l,mid,t));
		else chkmax (now,query (rs(x),mid + 1,r,t));
		return now;
	}
}tree;

signed main(){
	freopen ("array.in","r",stdin);
	freopen ("array.out","w",stdout);
	read (n),read (C);
	for (Int i = 1;i <= n;++ i) read (a[i]);
	for (Int i = 1;i <= n;++ i) tmp[i] = a[i];
	sort (tmp + 1,tmp + n + 1),cnt = unique (tmp + 1,tmp + n + 1) - tmp - 1;
	for (Int i = 1;i <= n;++ i) a[i] = lower_bound (tmp + 1,tmp + cnt + 1,a[i]) - tmp;
	for (Int i = 1;i <= n;++ i){
		if (i == 1) f[i] = 0;
		else f[i] = tree.query (rt,1,cnt,a[i]) + 1ll * tmp[a[i]] * tmp[a[i]] + C;
		tree.modify (rt,1,cnt,-2 * tmp[a[i]],f[i] + 1ll * tmp[a[i]] * tmp[a[i]]); 
	}
	write (f[n]),putchar ('\n');
	return 0;
}

T2

Description

一个长度为 \(n\) 的序列,可以查 \(2\) 次位置上的值,或是 \(30\) 次查询位置集合中两两差的绝对值集合。\(n\le 250\)

Solution

不难发现我们可以先查一次全集,可以知道极差,那么我们就可以二分出位置较大的最小值或是最大值 \(x\)。我们考虑对于二进制下的每一位集合,查该集合以及该集合并上 \(x\) 的差的绝对值集合,就可以知道他们与 \(x\) 的差值。又因为每个值两两不同,所以对于一个值,最多每个位置查询出现一次,所以我们就可以确定位置。我们还可以找到另一个最值,查一下就知道 \(x\) 是最大还是最小了。查询次数 \(3\log n\)

Code

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

#define Int register int

template <typename T> inline void chkmax (T &a,T b){a = max (a,b);}
template <typename T> inline void chkmin (T &a,T b){a = min (a,b);}

void find(int n, int M1, int M2){
	set <int> Spos[25];
	vector<int> S, ret;ret.resize (n);
	int l = 1,r = n,ans = 0;
	for (Int i = 0;i < n;++ i) S.push_back (i);
	vector<int> H = qry2 (S);int mxv = 0;
	for (Int v : H) chkmax (mxv,v);
	while (l <= r){
		int mid = l + r >> 1;
		S.clear ();for (Int j = 1;j <= mid;++ j) S.push_back (j - 1);
		H = qry2 (S);int maxv = 0;for (Int v : H) chkmax (maxv,v);
		if (mxv == maxv) ans = mid,r = mid - 1;
		else l = mid + 1;
	}
	for (Int i = 0;(1 << i) <= n;++ i){
		S.clear ();
		for (Int x = 1;x <= n;++ x) if (x >> i & 1) if (x != ans) S.push_back (x - 1);
		vector<int> H1 = qry2 (S);S.push_back (ans - 1);vector <int> H2 = qry2 (S);
		sort (H1.begin(),H1.end()),sort (H2.begin(),H2.end());int s2 = 0;
		for (Int s1 = 0;s1 < H1.size();++ s1){
			while (H2[s2] != H1[s1]) Spos[i].insert (H2[s2]),s2 ++;
			s2 ++;
		}
		while (s2 < H2.size()) Spos[i].insert (H2[s2]),s2 ++;
	}
	set <int> All;
	for (Int i = 0;(1 << i) < n;++ i) for (Int v : Spos[i]) All.insert (v);
	auto it = All.end();-- it;int v = (*it),y = 0;All.erase (it);
	for (Int i = 0;(1 << i) <= n;++ i) if (Spos[i].find (v) != Spos[i].end()) y += (1 << i),Spos[i].erase (v);
	ret[ans - 1] = qry1 (ans - 1),ret[y - 1] = qry1 (y - 1);
	for (Int v : All){
		int pos = 0;
		for (Int i = 0;(1 << i) < n;++ i) if (Spos[i].find (v) != Spos[i].end()) pos += (1 << i),Spos[i].erase (v);
		if (ret[ans - 1] < ret[y - 1]) ret[pos - 1] = ret[ans - 1] + v;
		else ret[pos - 1] = ret[ans - 1] - v;
	}
	answer (ret);
}

T3

Description

给出集合 \(S,T\),问构造一个长度为 \(L\) 的序列 \(a\) 使得\(\forall i\in [1,L],s.t. a_i\in S\) 且任意前缀异或值 \(\notin T\)

\(|S|\le 35,|T|\le 20,L\le 4000\)

Solution

不难发现我们可以直接容斥,只需要钦定若干位置属于 \(T\) 即可。那么我们可以直接设 \(\text{dp}_{i,j}\) 表示考虑前面 \(i\) 位,第 \(i\) 个是 \(T_j\) 的容斥贡献。

考虑如何计算一个长度从 \(S\) 中选使得异或和为 \(v\) 的方案数。我们可以先对 \(S\) 构造线性基,如果大小 \(\le n/2\),那么我们只需要计算:

\[\text{FWT}(\prod_{i=1}^{n} (1+x^{varphi(s_i)}y)) \]

然后对于每个 \(x_i\) 位置的 \(y_j\) 就表示异或和为 \(i\) 用了 \(j\) 个选奇数次的 \(s_k\),然后方案就是系数乘上 \(f_{l,j}\)。其中,\(f_{l,i}\) 表示长度为 \(l\) 的序列有 \(i\) 个选奇数次的值的方案数。这个玩意我们可以使用生成函数算出来,你发现假如有 \(k\) 个选奇数次,那就是:

\[(\frac{1}{2})^n(e^x+e^{-x})^{n-k}(e^x-e^{-x})^k \]

可以直接展开,然后算对每一位的贡献。

对于线性基大小 \(>n/2\),可以发现不在线性基中的元素个数 \(\le n/2\),那么我们可以枚举他们选择奇偶性,就可以确定线性基里面的选择方案。

然后考虑如何优化 dp,我们发现如果我们把答案写成向量多项式 \(F\),转移写成矩阵多项式 \(G\),就有关系:

\[F=T-G\times F \]

其中 \(T\) 的每一位就是从 \(0\) 号位直接转移的向量多项式。然后我们就可以直接求逆求了。实现的比较丑陋。

Code

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

#define Int register int
#define mod 998244353
#define MAXN 4005
#define MAXM 45

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

int n,m,L,s[MAXN],t[MAXN],fac[MAXN],ifac[MAXN],dp[MAXN][MAXM];

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 binom (int a,int b){return mul (fac[a],mul (ifac[b],ifac[a - b]));}

#define poly vector<int>
#define SZ(A) ((A).size())
#define MAXX 800005

void putout (poly A){
	cout << SZ(A) << ": ";
	for (Int i = 0;i < SZ(A);++ i) cout << A[i] << " , ";cout << endl;
}

int rev[MAXX],w[MAXX];
void init_ntt (){
	int lim = 1 << 18;
	for (Int i = 0;i < lim;++ i) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << 17);
	int Wn = qkpow (3,(mod - 1) / lim);w[lim >> 1] = 1;
	for (Int i = lim / 2 + 1;i < lim;++ i) w[i] = mul (w[i - 1],Wn);
	for (Int i = lim / 2 - 1;i;-- i) w[i] = w[i << 1];
}

void ntt (poly &a,int type){
#define G 3
#define Gi 332748118
	static int d[MAXX];int lim = a.size();
	for (Int i = 0,z = 18 - __builtin_ctz(lim);i < lim;++ i) d[rev[i] >> z] = a[i];
	for (Int i = 1;i < lim;i <<= 1)
		for (Int j = 0;j < lim;j += i << 1)
			for (Int k = 0;k < i;++ k){
				int x = mul (w[i + k],d[i + j + k]);
				d[i + j + k] = dec (d[j + k],x),d[j + k] = add (d[j + k],x);
			}
	for (Int i = 0;i < lim;++ i) a[i] = d[i] % mod;
	if (type == -1){
		reverse (a.begin() + 1,a.begin() + lim);
		for (Int i = 0,Inv = qkpow (lim,mod - 2);i < lim;++ i) a[i] = mul (a[i],Inv);
	}
#undef G
#undef Gi 
}

poly operator * (poly A,poly B){
	int lim = 1,l = 0,len = SZ(A) + SZ(B) - 1;
	while (lim < SZ(A) + SZ(B)) lim <<= 1,++ l;
	A.resize (lim),B.resize (lim),ntt (A,1),ntt (B,1);
	for (Int i = 0;i < lim;++ i) A[i] = mul (A[i],B[i]);
	ntt (A,-1),A.resize (len);
	return A;
}

poly operator ^ (poly A,poly B){
	int l = 0,len = SZ(A) + SZ(B) - 1;poly C;C.resize (len);
	for (Int i = 0;i < SZ(A);++ i)
		for (Int j = 0;j < SZ(B);++ j) Add (C[i + j],mul (A[i],B[j]));
	return C;
}

poly operator + (poly A,poly B){
	int len = max (SZ(A),SZ(B));A.resize (len),B.resize (len);
	for (Int i = 0;i < len;++ i) Add (A[i],B[i]);
	return A;
}

poly operator - (poly A,poly B){
	int len = max (SZ(A),SZ(B));A.resize (len),B.resize (len);
	for (Int i = 0;i < len;++ i) A[i] = dec (A[i],B[i]);
	return A;
}

poly operator * (poly A,int b){
	for (Int i = 0;i < SZ(A);++ i) A[i] = mul (A[i],b);
	return A;
}

int siz,ind[35],val[35],dfn[35],Siz[35];
void build_base (int v,int id){
	int cnt = 0;
	for (Int i = 30;~i;-- i)
		if (v >> i & 1){
			if (!ind[i]){
				siz ++,dfn[i] = siz,val[i] = v,ind[i] = id,Siz[i] = cnt ^ (1 << i);
				return ;
			}
			v ^= val[i],cnt ^= Siz[i];
		}
}

void fwt (poly *f,int type){
	for (Int R = 2,mid = 1;R <= (1 << siz);R <<= 1,mid <<= 1)
		for (Int i = 0;i < (1 << siz);i += R)
			for (Int j = 0;j < mid;++ j){
				f[i + j] = f[i + j] + f[i + j + mid];
				f[i + j + mid] = f[i + j] - f[i + j + mid] * 2;
				f[i + j] = f[i + j] * type,f[i + j + mid] = f[i + j + mid] * type; 
			}
}

bool vis[MAXM];
poly f[MAXM][131075];int stp[MAXN][21][21];

struct Matrix{
	int mat[21][21];
	Matrix(){memset (mat,0,sizeof (mat));}
	void clear(){memset (mat,0,sizeof (mat));}
	Matrix operator * (const Matrix &p)const{
		Matrix New;
		for (Int i = 1;i <= m;++ i)
			for (Int j = 1;j <= m;++ j)
				for (Int k = 1;k <= m;++ k) Add (New.mat[i][k],mul (mat[i][j],p.mat[j][k]));
		return New;
	}
	Matrix operator + (const Matrix &p)const{
		Matrix New;
		for (Int i = 1;i <= m;++ i)
			for (Int j = 1;j <= m;++ j) New.mat[i][j] = add (mat[i][j],p.mat[i][j]);
		return New;
	}
	Matrix operator - (const Matrix &p)const{
		Matrix New;
		for (Int i = 1;i <= m;++ i)
			for (Int j = 1;j <= m;++ j) New.mat[i][j] = dec (mat[i][j],p.mat[i][j]);
		return New;
	} 
	Matrix operator * (const int &p)const{
		Matrix New;
		for (Int i = 1;i <= m;++ i)
			for (Int j = 1;j <= m;++ j) New.mat[i][j] = mul (mat[i][j],p);
		return New;
	}
	int * operator [] (int key){return mat[key];}
	void putout (){
		for (Int i = 1;i <= m;++ i){
			for (Int j = 1;j <= m;++ j) cout << mat[i][j] << " ";
			cout << endl;
		}
	}
}I;

#define Poly vector<Matrix>
poly Ts[21][21];
void NTT (Poly &a,int type){
	int len = SZ(a);
	for (Int i = 1;i <= m;++ i)
		for (Int j = 1;j <= m;++ j){
			Ts[i][j].resize (len);
			for (Int k = 0;k < SZ(a);++ k) Ts[i][j][k] = a[k][i][j];
			ntt (Ts[i][j],type);
 			for (Int k = 0;k < SZ(a);++ k) a[k][i][j] = Ts[i][j][k];
		}
}

Poly operator * (Poly A,Poly B){
	int lim = 1,l = 0,len = SZ(A) + SZ(B) - 1;
	while (lim <= SZ(A) + SZ(B)) lim <<= 1,++ l;
	A.resize (lim),B.resize (lim),NTT (A,1),NTT (B,1);
	for (Int i = 0;i < lim;++ i) A[i] = A[i] * B[i];
	NTT (A,-1),A.resize (len);
	return A;	
}

Poly inv (Poly a,int N){
	Poly b,c;b.resize (1);
	for (Int i = 1;i <= m;++ i) b[0][i][i] = 1;
	for (Int l = 4;(l >> 2) < N;l <<= 1){
		c.resize (l >> 1);
		for (Int i = 0;i < (l >> 1);++ i) if (i < N) c[i] = a[i];else c[i].clear();
		c.resize (l),b.resize (l),NTT (c,1),NTT (b,1);
		for (Int i = 0;i < l;++ i) b[i] = b[i] * (I * 2 - c[i] * b[i]);
		NTT (b,-1),b.resize (l >> 1);
	}
	return b;
}
Poly inv (Poly a){return inv (a,SZ(a));}

int g[MAXN][MAXM],pw[MAXN << 1];
int upd (int x){return x < 0 ? x + mod : x;}

void init (){
	int inv2 = (mod + 1) >> 1,iv = qkpow (inv2,n);
	for (Int k = 0;k <= n;++ k){
		for (Int j = -n;j <= n;++ j) pw[n + j] = 1;
		for (Int l = 0;l <= L;++ l){
			for (Int i = 0;i <= n - k;++ i)
				for (Int j = 0;j <= k;++ j){
					int v = mul (binom (n - k,i),binom (k,j));
					if (k - j & 1) v = mod - v;
					Add (dp[l][k],mul (pw[2 * (i + j)],mul (v,iv)));
				}
			for (Int i = -n;i <= n;++ i) pw[n + i] = mul (pw[n + i],upd (i));
		}
	}
}

int tmpS[MAXM][MAXM];
int getsum (int v){
	int sum = 0;
	for (Int i = 30;~i;-- i) if (v >> i & 1){
		if (!val[i]) return -1;
		sum ^= Siz[i],v ^= val[i];
	}
	return sum;
} 

int tsum[21][21][MAXM];

signed main(){
	freopen ("randomxor.in","r",stdin);
	freopen ("randomxor.out","w",stdout);
	read (n,m,L);
	for (Int i = 1;i <= m;++ i) I[i][i] = 1;
	fac[0] = 1;for (Int i = 1;i <= L;++ i) fac[i] = mul (fac[i - 1],i);
	ifac[L] = qkpow (fac[L],mod - 2);for (Int i = L;i;-- i) ifac[i - 1] = mul (ifac[i],i);
	for (Int i = 1;i <= n;++ i) read (s[i]);
	for (Int i = 1;i <= m;++ i) read (t[i]);
	init (),init_ntt ();
	for (Int i = 1;i <= n;++ i) build_base (s[i],i);
	if (siz <= 15){
		for (Int i = 1;i <= n;++ i){
			int pos = 0,v = s[i];
			for (Int j = 30;~j;-- j) if (v >> j & 1) pos |= (1 << dfn[j] - 1),v ^= val[j];
			poly h1 = poly(1,1),h2;h2.resize (2),h2[1] = 1;
			for (Int k = 0;k < (1 << siz);++ k){
				int s2 = __builtin_popcount (k & pos);
				f[i][k] = h1 + h2 * (s2 & 1 ? (mod - 1) : 1);
			}
		}
		for (Int i = 0;i < (1 << siz);++ i) for (Int k = 2;k <= n;++ k) f[1][i] = f[1][i] ^ f[k][i];
		fwt (f[1],mod + 1 >> 1);
		for (Int k1 = 0;k1 <= m;++ k1)
			for (Int k2 = 1;k2 <= m;++ k2){
				int nedv = t[k2] ^ t[k1],pos = 0,v = nedv;
				for (Int i = 30;~i;-- i) if (v >> i & 1) pos |= (1 << dfn[i] - 1),v ^= val[i];
				if (v) continue;
				for (Int l = 1;l <= L;++ l){
					for (Int i = 0;i < SZ(f[1][pos]) && i <= l;++ i)
						Add (stp[l][k1][k2],mul (f[1][pos][i],dp[l][i]));
				}
			}
	}
	else{
		for (Int i = 30;~i;-- i) if (ind[i]) vis[ind[i]] = 1;
		vector <int> Spos;
		for (Int i = 1;i <= n;++ i) if (!vis[i]) Spos.push_back (i);
		for (Int k1 = 0;k1 <= m;++ k1) for (Int k2 = 1;k2 <= m;++ k2) tmpS[k1][k2] = getsum (t[k1] ^ t[k2]);
		for (Int S = 0;S < (1 << Spos.size());++ S){
			int nedv = 0,tot = 0,sum = 0,psum;
			for (Int i = 0;i < Spos.size();++ i) if (S >> i & 1) nedv ^= s[Spos[i]],tot ++;psum = getsum (nedv);
			for (Int k1 = 0;k1 <= m;++ k1)
				for (Int k2 = 1;k2 <= m;++ k2){
					if (tmpS[k1][k2] == -1) continue;
					int bit = __builtin_popcount (psum ^ tmpS[k1][k2]);
					tsum[k1][k2][tot + bit] ++;
				}
		}
		for (Int l = 1;l <= L;++ l) for (Int k1 = 0;k1 <= m;++ k1) for (Int k2 = 1;k2 <= m;++ k2) for (Int ts = 0;ts <= n;++ ts) Add (stp[l][k1][k2],mul (tsum[k1][k2][ts],dp[l][ts]));
	}
	Poly G,T;G.resize (L),T.resize (L);
	for (Int k1 = 1;k1 <= m;++ k1) G[0][k1][k1] = 1;
	for (Int i = 1;i < L;++ i) for (Int k1 = 1;k1 <= m;++ k1) for (Int k2 = 1;k2 <= m;++ k2) G[i][k1][k2] = stp[i][k1][k2];
	for (Int i = 1;i <= L;++ i) for (Int k = 1;k <= m;++ k) T[i - 1][k][1] = stp[i][0][k];
	Poly F = inv (G,L) * T;
	int ans = qkpow (n,L);
	for (Int i = 0;i < L;++ i) for (Int j = 1;j <= m;++ j) Sub (ans,mul (F[i][j][1],qkpow (n,L - 1 - i)));
	write (ans),putchar ('\n');
	return 0;
}
posted @ 2022-02-09 16:37  Dark_Romance  阅读(58)  评论(0编辑  收藏  举报