• 2021-07-09/11 部分集训题目题解


    2021-07-09

    查拉图斯特拉如是说

    题目传送门

    Description

    Solution

    有多项式快速多点求值的算法,我写的是另外一种更加简单的 (Theta(nlog n)) 的算法。

    我们可以发现,我们就是要求:

    [sum_{k=0}^{n} inom{n}{k}sum_{i=0}^{m} a_i imes k^i ]

    [sum_{i=0}^{m} a_i imes sum_{k=0}^{n} inom{n}{k} imes k^i ]

    也就是说,我们只需要快速知道:

    [F(x)=sum_{i=0}^{infty} frac{x^i}{i!}sum_{k=0}^{n} inom{n}{k} imes k^i ]

    [=sum_{k=0}^{n} inom{n}{k} sum_{i=0}^{infty} frac{(xk)^i}{i!} ]

    [=sum_{k=0}^{n} inom{n}{k} (e^x)^k ]

    [=(e^x+1)^n ]

    这个直接多项式 (ln, ext{exp}) 即可。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 800005
    
    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');}
    
    #define mod 998244353
    #define Gi 332748118
    #define G 3
    
    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){
    	b %= mod - 1;
    	if (b < 0) b += mod - 1;
    	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);}
    
    typedef vector<int> poly;
    
    int w[MAXN],rev[MAXN];
    #define SZ(A) ((int)A.size())
    
    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[MAXN];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 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;
    }
    
    int sqri,Ansf;
    
    struct node{
    	int real,imag;
    	node (int _real,int _imag) : real (_real) , imag (_imag) {}
    	node operator * (node b){return node (add (1ll * real * b.real % mod,1ll * imag * b.imag % mod * sqri % mod),add (1ll * real * b.imag % mod,1ll * b.real * imag % mod));}
    	node operator + (node b){return node (add (real,b.real),add (imag,b.imag));}
    	node operator ^ (int b){node a = *this,res = node (1,0);for (;b;b >>= 1,a = a * a) if (b & 1) res = res * a;return res;}
    };
    
    bool check_if_qs (int n){//判断是否是一个二次剩余 
    	return qkpow (n,(mod - 1) >> 1) == 1;
    }
    
    bool tryit (int n){
    	if (n == 0){
    		puts ("0");
    		return 1;
    	}
    	int a = rand ();sqri = dec (mul (a,a),n);
    	if (!a || !check_if_qs (sqri)){
    		int x0 = (node (a,1) ^ (mod + 1 >> 1)).real;
    		Ansf = min (x0,mod - x0);
    		return 1;
    	}
    	else return 0;
    } 
    
    int Work (int n){
    	while (1) if (tryit (n)) break;
    	return Ansf;
    }
    
    poly operator * (poly A,int B){
    	for (Int i = 0;i < SZ(A);++ i) A[i] = mul (A[i],B);
    	return A;
    }
    poly operator * (int B,poly A){
    	for (Int i = 0;i < SZ(A);++ i) A[i] = mul (A[i],B);
    	return A;	
    }
    
    poly inv (poly A,int n){
    	if (n == 1) return poly(1,qkpow (A[0],mod - 2));
    	poly F1,F0 = inv (A,(n + 1) >> 1);poly tmp;tmp.resize (n);for (Int i = 0;i < n;++ i) tmp[i] = A[i];
    	F1 = F0 * 2 - F0 * F0 * A,F1.resize (n);
    	return F1;
    }
    poly inv(poly A){return inv(A,SZ(A));}
    
    #define inv2 (mod+1)/2
    
    poly Sqrt(poly A,int n){
    	if (n == 1) return poly(1,Work(A[0]));
    	poly F1,F0 = Sqrt(A,(n + 1) >> 1);poly tmp;tmp.resize (n);for (Int i = 0;i < n;++ i) tmp[i] = A[i];
    	F1 = (A * inv(F0,n) + F0) * (inv2),F1.resize (n);
    	return F1; 
    }
    poly Sqrt (poly A){return Sqrt(A,SZ(A));}
    
    poly der (poly a){
    	for (Int i = 0;i < SZ (a) - 1;++ i) a[i] = mul (a[i + 1],i + 1);
    	a.pop_back ();return a;
    }
    poly ine (poly a){
    	a.push_back (0);
    	for (Int i = SZ (a) - 1;i;-- i) a[i] = mul (a[i - 1],qkpow (i,mod - 2));
    	a[0] = 0;return a;
    }
    
    poly ln (poly A,int n){
    	A = ine (der(A) * inv(A,n)),A.resize (n);
    	return A;
    }
    poly ln (poly A){return ln(A,SZ(A));} 
    
    void Putout (poly A){
    	cout << SZ(A) << ": ";
    	for (Int i = 0;i < SZ(A);++ i) cout << A[i] << " ";cout << endl;
    }
    
    poly exp (poly A,int n){
    	if (n == 1) return poly (1,1);
    	poly F1,F0 = exp (A,n + 1 >> 1);poly tmp;tmp.resize (n);for (Int i = 0;i < n;++ i) tmp[i] = A[i];
    	F1 = (poly(1,1) - ln(F0,n) + tmp) * F0,F1.resize (n);
    	return F1;
    }
    poly exp (poly A){return exp(A,SZ(A));}
    
    poly A;
    int n,m,a[MAXN],fac[MAXN],ifac[MAXN];
    
    signed main(){
    	freopen ("number.in","r",stdin);
    	freopen ("number.out","w",stdout);
    	init_ntt(),read (n,m),A.resize (m + 1);
    	fac[0] = 1;for (Int i = 1;i <= m;++ i) fac[i] = mul (fac[i - 1],i);
    	ifac[m] = qkpow (fac[m],mod - 2);for (Int i = m;i;-- i) ifac[i - 1] = mul (ifac[i],i);
    	for (Int i = 0;i <= m;++ i) read (a[i]),A[i] = mul (inv2,ifac[i] + (i == 0));
    	A = ln (A);for (Int i = 0;i <= m;++ i) A[i] = mul (A[i],n);A = exp (A);
    	for (Int i = 0,v = qkpow (2,n);i <= m;++ i) A[i] = mul (A[i],v);
    	int ans = 0;for (Int i = 0;i <= m;++ i) Add (ans,mul (a[i],mul (fac[i],A[i])));
    	write (ans),putchar ('
    ');
    	return 0;
    }
    

    橡树上的逃亡

    题目传送门

    Description

    Solution

    假设设 (s_x) 表示树上以 (x) 为根的子树内 ([L,R]) 的叶子数量,那么一个点 (u) 的父亲边的贡献就是:

    [1-(frac{s_u}{s_1})^k-(frac{s_1-s_u}{s_1})^k ]

    下面这个 (s_1) 可以提出来,也就是说我们只需要求 (sum s_u^k+sum (s_1-s_u)^k)

    然后你发现这个 (kle 10),你就可以把后面这个二项式展开,也就是只需要求 (sum s_u^i)

    这个可以树上做个前缀和和 ( ext{dfs}) 序上做前缀和解决。

    复杂度 (Theta(nk^2))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 998244353
    #define MAXN 200005
    #define MAXM 15
    
    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> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    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 type,n,q;
    vector <int> g[MAXN],lef;
    
    int C[MAXM][MAXM],fa[MAXN],tot[MAXN],siz[MAXN],tur[MAXN],rig[MAXN],lft[MAXN],dep[MAXN],st[MAXN][21],sum[MAXN][MAXM],lst1[MAXN][MAXM],lst2[MAXN][MAXM],lst3[MAXN][MAXM];
    void dfs (int u){
    	tot[u] = 1,lft[u] = n + 1;
    	for (Int i = 1;i <= 20;++ i) st[u][i] = st[st[u][i - 1]][i - 1];
    	if (!g[u].size()) siz[u] = 1,rig[u] = u,lft[u] = u,lef.push_back (u),tur[u] = lef.size();
    	for (Int v : g[u]) dep[v] = dep[u] + 1,st[v][0] = u,dfs (v),tot[u] += tot[v],siz[u] += siz[v],chkmax (rig[u],rig[v]),chkmin (lft[u],lft[v]);
    	if (u > 1) for (Int i = 0,v = 1;i <= 10;++ i) sum[u][i] = v,v = mul (v,siz[u]);
    }
    
    int getlca (int u,int v){
    	if (dep[u] < dep[v]) swap (u,v);
    	for (Int i = 20,dis = dep[u] - dep[v];~i;-- i) if (dis >> i & 1) u = st[u][i];
    	if (u == v) return u;
    	else{
    		for (Int i = 20;~i;-- i) if (st[u][i] ^ st[v][i]) u = st[u][i],v = st[v][i];
    		return st[u][0];
    	}
    }
    
    int getit (int lp,int rp,int lca,int K){
    	int con1 = dec (dec (sum[rp][K],sum[lp][K]),dec (lst1[rp][K],lst1[lca][K])),con2 = 0;
    	for (Int i = 0,v = 1;i <= K;++ i,v = mul (v,tur[lp] - 1)){
    		int fuc = dec (lst2[lp][K - i],lst2[lca][K - i]),tmp = mul (fuc,mul (C[K][i],v));
    		if (i & 1) Sub (con2,tmp);else Add (con2,tmp);
    	}
    	for (Int i = 0,v = 1;i <= K;++ i,v = mul (v,tur[rp] + 1)){
    		int fuc = dec (lst3[rp][K - i],lst3[lca][K - i]),tmp = mul (fuc,mul (C[K][i],v));
    		if (K - i & 1) Sub (con2,tmp);else Add (con2,tmp);
    	}
    	return add (con1,con2);
    }
    
    signed main(){
    	freopen ("tree.in","r",stdin);
    	freopen ("tree.out","w",stdout);
    	read (type,n,q);
    	for (Int i = 2;i <= n;++ i) read (fa[i]),g[fa[i]].push_back (i);
    	dfs (1);C[0][0] = 1;
    	for (Int i = 1;i <= 10;++ i){
    		C[i][0] = 1;
    		for (Int j = 1;j <= i;++ j) C[i][j] = add (C[i - 1][j],C[i - 1][j - 1]);
    	}
    	for (Int u = 2;u <= n;++ u){
    		for (Int i = 0;i <= 10;++ i) Add (sum[u][i],sum[u - 1][i]);
    		for (Int i = 0,v1 = 1,v2 = 1,v3 = 1;i <= 10;++ i,v1 = mul (v1,siz[u]),v2 = mul (v2,tur[rig[u]]),v3 = mul (v3,tur[lft[u]]))
    			lst1[u][i] = add (lst1[fa[u]][i],v1),lst2[u][i] = add (lst2[fa[u]][i],v2),lst3[u][i] = add (lst3[fa[u]][i],v3);
    	}
    	int lstans = 0;
     	while (q --> 0){
    		int L,R,K;read (L,R,K);
    		L ^= (type * lstans),R ^= (type * lstans);
    		if (lef[0] > R || lef[lef.size() - 1] < L) write (lstans = 0),putchar ('
    ');
    		else{
    			int lp = lower_bound (lef.begin(),lef.end(),L) - lef.begin(),rp = upper_bound (lef.begin(),lef.end(),R) - lef.begin() - 1,lca,all = rp - lp + 1;lp = lef[lp],rp = lef[rp],lca = getlca (lp,rp);
    			int iv = qkpow (all,mod - 2);iv = qkpow (iv,K);
    			if (all <= 1) write (lstans = 0),putchar ('
    ');
    			else{
    				int tmp = getit (lp,rp,lca,K);
    				for (Int i = 0,v = 1;i <= K;++ i,v = mul (v,all)){
    					int fuc = mul (C[K][i],mul (v,getit (lp,rp,lca,K - i)));
    					if (K - i & 1) Sub (tmp,fuc);else Add (tmp,fuc); 
    				}
    				int nsiz = rp - lp + dep[lp] - dep[lca];
    				int ans = dec (n - 1,mul (iv,add (tmp,mul (n - 1 - nsiz,qkpow (all,K)))));
    				write (lstans = ans),putchar ('
    ');
    			}
    		}
    	}
    	return 0;
    }
    

    2021-07-11

    悄悄话

    题目传送门

    Description

    Solution

    水题

    数学考试

    题目传送门

    Description

    Solution

    考虑没有限制的时候,因为 (L_i,R_i) 很小,所以我们可以网络流,即原点往汇点拉一条链,每条边的边权为 (f(i,j),jin [L_i,R_i]),然后做最小割。

    考虑限制,因为 (x_uge x_v+DRightarrow x_vle x_u-D),也就是说,我们可以 ((u,i))((v,i-D)) 连一条边权为 (infty) 的边。

    判断是否有解是否判断是否割掉了 (infty)

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define int long long
    #define MAXN 205
    
    template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c != ' ' && 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> void chkmax (T &a,T b){a = max (a,b);}
    template <typename T> void chkmin (T &a,T b){a = min (a,b);}
    
    int T,n,m,ind[MAXN][MAXN];
    
    struct node{
    	int a,b,c,d,L,R;
    }s[MAXN];
    
    int f (int i,int x){return s[i].a * x * x * x + s[i].b * x * x + s[i].c * x + s[i].d;}
    
    #define MAXM 200005
    #define MAXX 40005
    
    struct edge{
    	int v,w,nxt;
    }e[MAXM << 1];
    
    int top = 1,tot;
    int head[MAXX];
    
    void link (int u,int v,int w){
    	e[++ top] = edge {v,w,head[u]},head[u] = top;
    	e[++ top] = edge {u,0,head[v]},head[v] = top;
    }
    
    int dep[MAXX];
    
    bool BFS (int S,int T){
    	queue <int> q;q.push (S);
    	for (Int i = 0;i <= tot;++ i) dep[i] = -1;dep[S] = 0;
    	while (!q.empty()){
    		int u = q.front();q.pop ();
    		for (Int i = head[u];i;i = e[i].nxt){
    			int v = e[i].v,w = e[i].w;
    			if (w && dep[v] == -1) dep[v] = dep[u] + 1,q.push (v);
    		}
    	}
    	return dep[T] != -1;
    }
    
    int dfs (int s,int t,int flow){
    	if (s == t) return flow;int ans = 0;
    	for (Int i = head[s];i;i = e[i].nxt){
    		if (flow == 0) break;
    		int v = e[i].v,w = e[i].w;
    		if (dep[v] == dep[s] + 1 && w){
    			int del = dfs (v,t,min (flow,w));
    			e[i].w -= del,e[i ^ 1].w += del;
    			ans += del,flow -= del;
    		}
    	}
    	if (ans == 0) dep[s] = -1;
    	return ans;
    }
    
    #define inf 1e15
    #define mxv 1e8
    
    int MaxFlow (int s,int t){
    	int ans = 0;
    	while (BFS (s,t)) ans += dfs (s,t,inf);
    	return ans;
    }
    
    int led[MAXN];
    void Work (){
    	read (n,m),top = 1,memset (head,0,sizeof (head));
    	for (Int i = 1;i <= n;++ i) read (s[i].a,s[i].b,s[i].c,s[i].d,s[i].L,s[i].R);
    	int S = 0,T = 1;tot = 1;
    	for (Int i = 1;i <= n;++ i){
    		link (S,led[i] = ++ tot,inf);
    		for (Int j = s[i].L;j <= s[i].R;++ j,++ tot) link (tot,tot + 1,mxv - f (i,j));
    		link (tot,T,inf);
    	}
    	for (Int i = 1;i <= m;++ i){
    		int u,v,D;read (u,v,D);
    		for (Int j = s[u].L;j <= s[u].R;++ j)
    			if (s[v].L <= j - D && j - D <= s[v].R)
    				link (led[u] + j - s[u].L,led[v] + j - D - s[v].L,inf);
    			else if (s[v].R < j - D) link (led[u] + j - s[u].L,T,inf);
    	}
    	int tmp = MaxFlow (S,T);
    	if (tmp > inf) puts ("mei ji ge");
    	else write ((int)mxv * n - tmp),putchar ('
    ');
    }
    
    signed main(){
    	freopen ("sleep.in","r",stdin);
    	freopen ("sleep.out","w",stdout);
    	int T;read (T);
    	while (T --> 0) Work ();
    	return 0;
    }
    
  • 相关阅读:
    Unknown custom element: <el-container1>
    jQuery手机对话框插件
    告别2013,迎接2014
    淘宝开放平台主动通知的实现
    搭建JavaWeb服务器
    深入理解JavaScript执行上下文和执行栈
    为什么要选择学习Java?适合零基础的初学者的文章
    成为一名优秀的Java程序员9+难以置信的公式
    深入理解JavaScript作用域和作用域链
    JavaScript数据类型转换
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14999437.html
Copyright © 2020-2023  润新知