zoukankan      html  css  js  c++  java
  • 2021-05-27 集训题解

    T1

    Description

    给出一个大小为 (n) 的序列 (a_{1,2,...,n}),求出一个长度为 (n) 的序列 (b_{1,2,..,n}) 使得任意一个 (a_i) 都可以通过 (b_j+b_k) 求到。

    (nle 30)

    Solution

    首先如果存在 (a_i) 为偶数的话,那么一定有解。

    如果我们把每一个 (a_i) 的拆分看作一条边,那么,(b) 序列就是一个 (n) 个点 (n) 条边的图。所以一定存在环。

    假设我们环的大小为 (k),环上的 (b)(b_1,b_2,...,b_k),那么我们可以得到 (b_1+b_2=a_1,b_2+b_3=a_2,...,b_k+b_1=a_k),我们就可以得到:

    [sum_{i=1}^{k} a_i=2sum_{i=1}^{k} b_i ]

    因为 (a_i) 为偶数的情况已经判断了,所以 (k) 一定是偶数。

    所以

    [a_1+a_3+...+a_{k-1}=sum_{i=1}^{k} b_i=a_2+a_4+...+a_k ]

    所以合法的情况就是存在两个大小相等的集合使得 (sum a) 相同。这个可以折半搜索,复杂度 (Theta(3^{n/2}))

    Code(写的太丑了,过不了)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define W 1000000000009
    #define int long long
    #define MAXN 35
    
    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');}
    
    int n,len,a[MAXN];
     
    unordered_map <int,int> mp;
    
    #define pii pair<int,int>
    
    bool flg;
    pii fucans;
    
    void dfs (int now,int lim,int Sta,int pw,int totA1,int totA2,int SumA1,int SumA2,bool tag){
    	if (flg) return ;
    	if (now > lim){
    		if (tag == 0) mp[SumA1 - SumA2 + (totA1 - totA2) * W] = Sta;
    		else{
    			int S = mp[SumA2 - SumA1 + (totA2 - totA1) * W];
    			if (S) fucans = make_pair (S,Sta),flg = 1;
    		}
    		return ;
    	}
    	dfs (now + 1,lim,Sta,pw << 2,totA1,totA2,SumA1,SumA2,tag);
    	dfs (now + 1,lim,Sta + pw,pw << 2,totA1 + 1,totA2,SumA1 + a[tag * len + now],SumA2,tag);
    	dfs (now + 1,lim,Sta + pw * 2,pw << 2,totA1,totA2 + 1,SumA1,SumA2 + a[tag * len + now],tag);
    }
    
    signed main(){
    	read (n),len = n >> 1;vector <int> S;
    	for (Int i = 1;i <= n;++ i) read (a[i]);
    	for (Int i = 1;i <= n;++ i) if (a[i] % 2 == 0){
    		S.push_back (a[i] / 2);
    		for (Int j = 1;j <= n;++ j) if (i ^ j) S.push_back (a[j] - a[i] / 2);
    		goto there;
    	}
    	dfs (1,len,0,1,0,0,0,0,0),
    	dfs (1,n - len,0,1,0,0,0,0,1);
    	if (flg){
    		vector <int> A1,A2;int S1 = fucans.first,S2 = fucans.second;
    		for (Int i = 1;i <= len;++ i){
    			int t = (S1 >> ((i - 1) * 2) & 3);
    			if (t == 1) A1.push_back (a[i]);
    			else if (t == 2) A2.push_back (a[i]);  
    			else S.push_back (a[i]); 
    		}
    		for (Int i = 1;i <= n - len;++ i){
    			int t = (S2 >> ((i - 1) * 2) & 3);
    			if (t == 1) A1.push_back (a[len + i]);
    			else if (t == 2) A2.push_back (a[len + i]);  
    			else S.push_back (a[len + i]); 
    		}
    		S.push_back (0); 
    		for (Int i = 0,lst = 0;i < A1.size();++ i){
    			S.push_back (A1[i] - lst),lst = A1[i] - lst;
    			if (i != A2.size() - 1) S.push_back (A2[i] - lst),lst = A2[i] - lst;  
    		}
    		goto there;
    	}
    	puts ("No");return 0;
    	there:
    	for (Int i = 1;i <= n;++ i){
    		bool tag = 0;
    		for (Int y1 = 0;y1 < n;++ y1)
    			for (Int y2 = 0;y2 < n;++ y2)
    				if (S[y1] + S[y2] == a[i]) tag = 1;
    		if (!tag){
    			puts ("No");
    			return 0;
    		}
    	}
    	puts ("Yes");
    	for (Int i = 0;i < n;++ i) write (S[i]),putchar (' ');putchar ('
    ');
    	for (Int i = 1;i <= n;++ i){
    		for (Int y1 = 0;y1 < n;++ y1)
    			for (Int y2 = 0;y2 < n;++ y2)
    				if (S[y1] + S[y2] == a[i]){
    					cout << y1 + 1 << " " << y2 + 1 << endl;
    					goto here;
    				}
    		here:;
    	}	
    	return 0;
    }
    

    T2

    Description

    有一个 (n) 个点,(m) 条边的图,满足所有点双大小 (le s),有一些点已经钦定了颜色,还有一些可以从 ([1,k]) 中任选。问最小颜色联通数。

    (nle 10^5,kle 20,sle 6)

    Solution

    可以先直接建出广义圆方树,注意原点一定连方点,这样好讨论。

    考虑设 (f_{u,c}) 表示圆方树上以 (u) 为根的子树 (u)(c) 的最小操作次数,如果 (u) 为方点,表示 (u) 的父亲染 (c)

    那么如果 (u) 是圆点,转移式就是:

    [f_{u,c}=1+sum_{vin son_u} (f_{v,c}-1) ]

    如果 (u) 是方点,我们就需要多讨论一下。

    我们设 (g_{S,c}) 表示点双中的一个连通块 (S) 都染颜色 (c) 的最小花费。

    那么我们可以得到:

    如果 (S) 联通 (g_{S,c}=1+sum_{uin S} (f_{u,c}-1))

    否则 (g_{S,c}=infty)

    判联通可以递推预处理。

    (G(S)=max(g_{S,c}))(h(S)) 表示解决掉 (S) 的最小花费。

    可以得到 (h(S)=G(T)+h(S-T)),而我们的 (f_{u,c}=min(g_{S,c}+h(H-S))),其中 (H) 表示全集。

    复杂度是 (Theta(n(3^s+2^s imes s))) 的。

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define MAXN 1000005
    #define inf 1900007
    
    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');}
    
    int n,m,K,s;
    void chkmin (int &a,int b){a = min (a,b);}
    
    struct edge{
    	int v,nxt;
    }e[MAXN << 1];
    int toop = 1,head[MAXN];
    
    void add_edge (int u,int v){
    	e[++ toop] = edge {v,head[u]},head[u] = toop;
    	e[++ toop] = edge {u,head[v]},head[v] = toop;
    }
    
    int tp,ind,cnt,c[MAXN],dfn[MAXN],low[MAXN],stk[MAXN];
    vector <int> G[MAXN];
    void link (int u,int v){
    	G[u].push_back (v),G[v].push_back (u); 
    }
    
    void Tarjan (int u,int pre){
    	dfn[u] = low[u] = ++ ind,stk[++ tp] = u;
    	for (Int i = head[u];i;i = e[i].nxt) if ((i ^ 1) != pre){
    		int v = e[i].v;
    		if (!dfn[v]){
    			Tarjan (v,i),low[u] = min (low[u],low[v]);
    			if (low[v] >= dfn[u]){
    				link (u,++ cnt);
    				do{
    					link (cnt,stk[tp]);
    				}while (stk[tp --] != v);
    			}
    		}
    		else low[u] = min (low[u],dfn[v]);
    	}
    }
    
    bool uni[1 << 7];
    int sz,f[MAXN][21],h[1 << 7],g[MAXN][1 << 7],id[MAXN],ch[MAXN],nxtS[MAXN];
    void dfs (int u,int fa){
    	if (u <= n){
    		for (Int i = 1;i <= K;++ i) if (!c[u] || c[u] == i) f[u][i] = 1;else f[u][i] = inf;
    		for (Int v : G[u]) if (v ^ fa){
    			dfs (v,u);
    			for (Int i = 1;i <= K;++ i) f[u][i] += f[v][i] - 1;
    		}
    	}
    	else{
    		for (Int v : G[u]) if (v ^ fa) dfs (v,u);
    		sz = 0;
    		for (Int v : G[u]) id[v] = sz,ch[sz ++] = v;
    		for (Int v : G[u]){
    			for (Int i = head[v];i;i = e[i].nxt){
    				int r = e[i].v;
    				if (id[r] >= 0) nxtS[r] |= (1 << id[v]),nxtS[v] |= (1 << id[r]);
    			}
    		}
    		int up = (1 << sz) - 1;uni[0] = 1;
    		for (Int S = 1;S <= up;++ S){
    			uni[S] = 0;
    			for (Int i = 0;i < sz;++ i) if (S >> i & 1){
    				int lst = S ^ (1 << i);
    				if (uni[lst] && (!lst || (nxtS[ch[i]] & lst))){
    					uni[S] = 1;
    					break;
    				}
    			}
    			if (!uni[S]){
    				for (Int i = 0;i <= K;++ i) g[S][i] = inf;
    				continue;
    			}
    			for (Int i = 1;i <= K;++ i) g[S][i] = 1;
    			for (Int i = 0;i < sz;++ i) if ((S >> i & 1) && ch[i] != fa)
    				for (Int z = 1;z <= K;++ z) g[S][z] += f[ch[i]][z] - 1;
    			g[S][0] = inf;
    			for (Int i = 1;i <= K;++ i) chkmin (g[S][0],g[S][i]);
    		}
    		h[0] = 0;
    		for (Int S = 1;S <= up;++ S){
    			h[S] = inf;
    			for (Int T = S;T;T = (T - 1) & S) chkmin (h[S],g[T][0] + h[S ^ T]);
    		}
    		for (Int c = 1;c <= K;++ c){
    			f[u][c] = inf;
    			for (Int S = 1;S <= up;++ S) if (S >> id[fa] & 1) chkmin (f[u][c],g[S][c] + h[up ^ S]);
    		}
    		for (Int v : G[u]) id[v] = -1,nxtS[v] = 0;
    	}
    }
    
    signed main(){
    	read (n,m,K,s),cnt = n;
    	for (Int i = 1;i <= n;++ i) read (c[i]);
    	for (Int i = 1,u,v;i <= m;++ i) read (u,v),add_edge (u,v);
    	Tarjan (1,0),memset (id,-1,sizeof (id)),dfs (1,0);
    	int ans = inf;
    	for (Int i = 1;i <= K;++ i) chkmin (ans,f[1][i]);
    	write (ans),putchar ('
    ');
    	return 0;
    }
    

    T3

    Description

    有一个长度为 (n) 的序列 (a_{1,2,...,n}),对于每一个子串 ([l,r]),称函数 (f) 合法当且仅当 (f:A o A),其中 (A={1,2,...,m}),且 (f(a_{l+i-1})=a_{r-i+1})

    问所有子串的合法函数之和,对 (998244353) 取模。

    Solution

    可以看出的是,如果一个区间 ([l,r]) 存在合法函数,那么答案就是 (m^{m-t}),其中 (t) 表示不同 (a_i) 个数。

    然后我们发现实际上一个区间 ([l,r]) 合法当且仅当它本质上是一个回文串,本质是回文串当且仅当相对位置回文。那么我们设 (nxt_i) 表示与 (a_i) 相同的下一个位置,(pre_i) 表示与 (a_i) 相同的上一个位置,那么从 ([l+1,r-1]) 能推出 ([l,r]) 也合法当且仅当 (nxt_l>r) 或者 (a_{l+r-nxt_l}=a_r) 并且 (pre_r<l) 或者 (a_{l+r-pre_r}=a_l)

    然后你发现可以直接马拉车。复杂度 (Theta(n))

    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    #define Int register int
    #define mod 998244353
    #define MAXN 600005
    
    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');}
    
    int n,m,mid,maxr,a[MAXN],pw[MAXN],mp[MAXN],nxt[MAXN],pre[MAXN],sum[MAXN],cnt[MAXN],lst[MAXN],len[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;}
    void Add (int &a,int b){a = add (a,b);}
    void Sub (int &a,int b){a = dec (a,b);}
    
    signed main(){
    	read (n,m),pw[0] = 1;
    	for (Int i = 1;i <= m;++ i) pw[i] = mul (pw[i - 1],m);
    	for (Int i = 1;i <= n;++ i) read (a[i]);
    	for (Int i = 1;i <= n;++ i) pre[i] = lst[a[i]],lst[a[i]] = i;
    	for (Int i = 1;i <= m;++ i) lst[i] = n + 1;
    	for (Int i = n;i >= 1;-- i) nxt[i] = lst[a[i]],lst[a[i]] = i;
    	int ans = 0;
    	for (Int i = 1;i < 2 * n;++ i){
    		int l,r;
    		if (i < maxr){
    			int c = 2 * mid - i;
    			l = (c - len[c]) / 2 + 1,r = (c + len[c]) / 2,sum[i] = sum[c],cnt[i] = cnt[c];
    			while (r - l + 1 > maxr - i) Sub (sum[i],pw[m - cnt[i]]),cnt[i] -= nxt[l ++] > r,cnt[i] -= pre[r --] < l;
    			l += (i - c) / 2,r += (i - c) / 2; 
    		}
    		else{
    			if (i & 1) l = r = (i + 1) / 2,cnt[i] = 1;
    			else l = i / 2,r = l + 1,cnt[i] = 1 + (a[l] != a[r]);
    			sum[i] = pw[m - cnt[i]];
    		}
    		while (l > 1 && r < n && (nxt[l - 1] > r || a[i + 1 - nxt[l - 1]] == a[r + 1]) && (pre[r + 1] < l || (a[i + 1 - pre[r + 1]] == a[l - 1])))
    			cnt[i] += nxt[-- l] > r,cnt[i] += pre[++ r] < l,Add (sum[i],pw[m - cnt[i]]);
    		len[i] = r - l + 1,Add (ans,sum[i]);if (maxr <= i + len[i]) maxr = i + len[i],mid = i;
    	} 
    	write (ans),putchar ('
    ');
    	return 0;
    }
    
    
  • 相关阅读:
    CodeForces 731A Night at the Museum
    nyoj914 Yougth的最大化
    addEventListener或attachEvent都可以用bind代替
    答疑
    js判断是pc还是手机
    js实现xml转json和json转xml
    js实现xml转json
    margin重叠的解决办法
    去除移动端按钮点击时的阴影和rem标签垂直居中
    关于fiddler https 客户端 抓包配置
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/14820060.html
Copyright © 2011-2022 走看看