Live2D

2022/02/08 模拟赛题解

蚌埠住了,挂了 75% 的分。

T1

Description#

给出一个序列,分成若干段,把每段最大值取出来作为 B1,2,...,n,使 i=2((BiBi1)2+C) 最大。

n106

Solution#

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

不难发现,假如对于一个点它能作为最大值的最大区间为 [coli,cori],那么我们可以设 fi 表示前面 i 个考虑选了 i 的最大值,那么我们存在转移式:

fi=max(fj+(aiaj)2+C),cor_jcol_i1

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

Code#

Copy
#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 次查询位置集合中两两差的绝对值集合。n250

Solution#

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

Code#

Copy
#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 使得i[1,L],s.t.aiS 且任意前缀异或值 T

|S|35,|T|20,L4000

Solution#

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

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

FWT(i=1n(1+xvarphi(si)y))

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

(12)n(ex+ex)nk(exex)k

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

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

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

F=TG×F

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

Code#

Copy
#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 @   Dark_Romance  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示
CONTENTS