• Codeforces Round 612 题解


    [比赛链接]

    http://codeforces.com/contest/1286

    [题解]

    (A)

    不妨令 (dp_{i , j , 0 / 1}) 表示用了 (i) 个奇数 , (j) 个偶数 , 上一位奇数 / 偶数的最小值。

    考虑当前位置奇数的情况 , 有

    (dp_{i , j , 0} = min{dp_{i - 1 , j , 0} , dp_{i - 1 , j , 1} + 1})

    偶数同理。

    时间复杂度 (O(N ^ 3))

    (B)

    最简单的方式是构造一个排列。

    从根开始 (DFS) , 暴力合并子树 , 并将当前节点插入集合。

    时间复杂度 (O(N))

    (C)

    首先不难发现 :

    (1.) 把一个子串中字符乱序相当于给定了出现次数

    (2.) 对于同一个询问得到的两个子串,只有按照它们的长度才能把它们区分开。

    先来考虑简单版本的问题 , 考虑 ([1 , N]) 所有长度为 (i) 的子串和 ([2 , N]) 所有长度为 (i) 的子串 , 将各个字符做差 , 就得到了 ([1 , i]) 每个字符出现的次数 , 进一步将其与 ([1 , i - 1]) 做差 , 就得到了第 (i) 位的字符。

    这样的子串个数是 ({N choose 2} + {N + 1 choose 2} = N ^ 2)

    接着考虑困难版。

    不难发现 , 当 (ilelceilfrac N2 ceil) 时 , 原串每个字符贡献了 (min{j , N - i + 1 , i}) 次。而长度变为 (i - 1) 时 , 贡献变化当且仅当 (min(j,N-j+1)ge i) , 也就是 (jin[i , N - i + 1])

    于是长度为 (i) 的所有子串之和减去长度为 (i − 1) 的所有子串之和即为子串 ([i , N − i + 1]) ,可以直观理解成两个梯形的面积相减。

    然后再进行差分 , 就得到了 (i)((N - i + 1)) 位置上的字符可能是哪两个。

    这时就只需要知道前一半和后一半了。

    子串个数 (inom{n+1}2+(frac n2)^2<0.75(n+1)^2)

    (D)

    首先注意到一次碰撞必然发生在相邻的球之间 (相向而行、往左追击,往右追击)。

    把这 (2(N - 1)) 种情况预处理出来 , 并按照时间从小到大排序。

    这样 , 第 (i) 个碰撞作为第一次碰撞的概率即为前 ((i - 1)) 次都没发生 , 而第 (i) 次碰撞发生了的概率。

    那么每次相当于禁掉一个方向 , 而对于 (i) 禁了三个方向。

    (dp_{i , 0 / 1}) 表示前 (i) 个位置 , 上一个位置是向左 / 右的概率。

    直接转移是 (O(N ^ 2)) 的。 但可以用线段树维护矩阵优化。详见 [代码]

    时间复杂度 (O(NlogN))

    (E)

    考虑维护 (Border) 集合.

    在添加字符时不妨顺带维护 (fail) 数组 , 还可以记一个 (anc_{i}) 表示 (fail) 树上最近的祖先满足 (s_{x + 1} eq s_{fail_{i} + 1}).

    这样便可以在 (O(1)) 的时间内找出一个不合法的 (Border) 进行删除.

    既然要计算贡献 , 那么额外维护一个单调栈计算后缀最值即可.

    时间复杂度 (O(NlogN)) (均摊分析)

    (F)

    每次使用操作二时 , 不妨在 (i)(j) 间连一条无向边 , 这样就得到了图 (G).

    如果 (G) 中有环 , 那么还不如对环上每个点进行操作一.

    (G) 是一片森林. 而要做的便是最大化森林中树的棵数.

    考虑判断一个集合是否能连成一棵树?

    假设每次边的两个端点都是减去 (x) , 任选一点为根 , 那么每个点对根的贡献之和其深度有关.

    故满足条件当且仅当奇数深度点权和 = 偶数深度点权和.

    下面考虑可以给某些点 (+1) , 那么也就是 (|奇数点权和 - 偶数点权和| < |S|) 且奇偶性相同.

    直接枚举子集可以做到 (O(3 ^ N)).

    不难发现可以枚举大的那一半 , 时间复杂度 (O((1 + sqrt{2})^N))

    预处理完了以后便可以状压 (DP) 了 , 总时间复杂度 (O((1 + sqrt{2})^N + log{N} cdot N^2 cdot 2^N))

    [代码]

    (A)

    
    
        #include<bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        #define rep(i , l , r) for (int i = (l); i < (r); ++i)
         
        const int MN = 105;
         
        int N , A[MN] , dp[MN][MN][MN];
         
        int main() {
        	 
        	 scanf("%d" , &N);
        	 for (int i = 1; i <= N; ++i) scanf("%d" , &A[i]);
        	 memset(dp , 0x3f , sizeof(dp));
        	 dp[0][0][0] = dp[0][0][1] = 0;
        	 for (int i = 1; i <= N; ++i)
        	 for (int j = 0; j <= i; ++j) {
        	 	 if (A[i] % 2 || !A[i]) dp[i][j][1] = min(dp[i - 1][j][0] + 1 , dp[i - 1][j][1]);
        	 	 if (A[i] % 2 == 0 && j) dp[i][j][0] = min(dp[i - 1][j - 1][0] , dp[i - 1][j - 1][1] + 1);
        	 }
        	 printf("%d
    " , min(dp[N][N / 2][0] , dp[N][N / 2][1]));
             return 0; 
        }
    

    (B)

        #include<bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        #define rep(i , l , r) for (int i = (l); i < (r); ++i)
         
        const int MN = 2005;
         
        int N , c[MN] , ans[MN];
        vector < int > e[MN] , res;
         
        #define sz(a) (int)(a.size())
         
        inline int solve(int x) {
        	int ans = x > 0;
        	for (auto y : e[x]) ans += solve(y);
        	if (x) {
        		if (c[x] >= ans) {
        			printf("NO
    ");
        			exit(0);
        		}
        		res.insert(res.begin() + c[x] , x);
        	}
        	return ans;
        }
         
        int main() {
        	
        	 scanf("%d" , &N);
        	 for (int i = 1; i <= N; ++i) {
        	 	 int par; 
        	 	 scanf("%d%d" , &par , &c[i]);
        	 	 e[par].emplace_back(i);
        	 }
        	 solve(0);
        	 printf("YES
    ");
        	 for (int i = 0; i < sz(res); ++i)
        	 	 ans[res[i]] = i + 1;
        	 for (int i = 1; i <= N; ++i)
        	 	 printf("%d " , ans[i]);
             return 0;
        }
    
    

    (C)

        #include <bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        int n;
         
        auto query(int l , int r) {
            multiset < string > s;
            cout << "? " << l + 1 << " " << r << "
    ";
            for (int i = 0; i < (r - l) * (r - l + 1) / 2; ++i) {
            	string t;
            	cin >> t;
            	sort(t.begin() , t.end());
            	s.insert(t);
            }
            return s;
        }
         
        int main() {
            
            cin >> n;
            if (n <= 3) {
                string s;
                for (int i = 0; i < n; ++i)
                    s += *query(i , i + 1).begin();
                cout << "! " << s << "
    ";
                return 0;
            }
            int m = (n + 1) / 2;
            auto s = query(0 , m) , t = query(1 , m);
            for (auto &&i : t)
            	s.erase(s.find(i));
            vector < string > pre(s.begin() , s.end());
            sort(pre.begin() , pre.end() , [&](const auto &lhs , const auto &rhs) {
            	return lhs.length() < rhs.length();
            });
            string hf = pre[0];
            for (int i = 1; i < m; ++i) {
                vector < int > cnt(26);
                for (char c : pre[i])
                    ++cnt[c - 'a'];
                for (char c : pre[i - 1])
                    --cnt[c - 'a'];
                for (int j = 0; j < 26; ++j)
                    if (cnt[j] == 1)
                    	hf += 'a' + j;
            }
            string ans(n , 'a');
            auto f = query(0 , n);
            vector < vector < string > > sl(n);
            for (auto s : f)
            	sl[s.size() - 1].emplace_back(s);
            for (int i = 0; i < m; ++i)
            	ans[i] = hf[i];
            for (int i = 0; i < n / 2; ++i) {
                vector < int > cnt(26);
                for (auto &t : sl[n - i - 2])
                    for (char c : t)
                    	++cnt[c - 'a'];
                for (int j = 0; j <= i; ++j)
                    cnt[ans[j] - 'a'] -= j + 1;
                for (int j = n - i; j < n; ++j)
                    cnt[ans[j] - 'a'] -= n - j;
                for (int j = 0; j < 26; ++j)
                    if (cnt[j] % (i + 2) != 0)
                    	ans[n - 1 - i] = 'a' + j;
            }
            cout << "! " << ans << "
    ";
            return 0;
        }
    

    (D)

        #include <bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        const int MN = 1e5 + 5 , mod = 998244353;
         
        inline int qPow(int a , int b) {
            int c = 1;
            for (; b; b >>= 1 , a = 1ll * a * a % mod) if (b & 1) c = 1ll * c * a % mod;
            return c;
        } 
         
        const int inv = qPow(100 , mod - 2);
         
        struct node {
            int x , a , b , s , v;
        } C[MN * 2];
         
        int N;
        bool ban[MN][2][2];
        int idx[MN << 2] , val[MN << 2][2][2] , foo[MN][2] , md[MN << 2] , A[MN] , B[MN];
         
        inline void inc(int &x , int y) {
            x = x + y < mod ? x + y : x + y - mod;
        }
        inline bool cmp(node a , node b) {
            return 1LL * a.s * b.v < 1LL * a.v * b.s;
        }
        inline void pushup(int now) {
            for (int i = 0; i < 2; ++i) {
                for (int j = 0; j < 2; ++j) {
                    val[now][i][j] = 0; 
                    for (int x = 0; x < 2; ++x)
                    for (int y = 0; y < 2; ++y) {
                    	if (!ban[md[now]][x][y]) 
                    	   inc(val[now][i][j] , 1ll * val[now << 1][i][x] * val[now << 1 | 1][y][j] % mod);            	   
                    }
                }
            }
        }
        inline void build(int now , int l , int r) {
            if (l == r) {
                val[now][0][0] = foo[l][0];
                val[now][1][1] = foo[l][1];
                return;
            }
            int mid = l + r >> 1;
            md[now] = mid , idx[mid] = now;
            build(now << 1 , l , mid) , build(now << 1 | 1 , mid + 1 , r);
            pushup(now);
        }
         
        int main() {
            
            scanf("%d" , &N);
            for (int i = 1; i <= N; ++i) {
                scanf("%d%d%d" , &A[i] , &B[i] , &foo[i][1]);
                foo[i][1] = 1LL * foo[i][1] * inv % mod;
                foo[i][0] = (1 - foo[i][1] + mod) % mod;
            }
            build(1 , 1 , N);
            int M = 0;
            for (int i = 2; i <= N; ++i) {
                C[M++] = (node) {i - 1 , 1 , 0 , A[i] - A[i - 1] , B[i] + B[i - 1]};
                if (B[i] < B[i - 1]) C[M++] = (node) {i - 1 , 1 , 1 , A[i] - A[i - 1] , B[i - 1] - B[i]};
                if (B[i] > B[i - 1]) C[M++] = (node) {i - 1 , 0 , 0 , A[i] - A[i - 1] , B[i] - B[i - 1]};
            }
            sort(C , C + M , cmp);
            int ans = 0 , lst = 1;
            for (int i = 0; i < M; ++i) {
                ban[C[i].x][C[i].a][C[i].b] = 1;
                for (int now = idx[C[i].x]; now; now >>= 1) pushup(now);
                int cur = (((val[1][0][0] + val[1][0][1]) % mod) + ((val[1][1][0] + val[1][1][1]) % mod)) % mod;
                inc(ans , 1ll * C[i].s * qPow(C[i].v , mod - 2) % mod * (((lst - cur + mod) % mod) % mod) % mod); 
                lst = cur;
            }
            printf("%d
    " , ans);
            return 0;
        }
    

    (E)

        #include<bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        #define rep(i , l , r) for (int i = (l); i < (r); ++i)
         
        const int MN = 6e5 + 5, M = 1 << 30;
        const LL mod = 1e18;
         
        map<int , int> cnt;
        int N , w[MN], fail[MN], anc[MN], st[MN], top;
        LL res; 
        char s[MN];
         
        struct BigInt {
        	LL a , b;
        	inline void operator += (const LL &x) {
        		if ((b += x) >= mod) b -= mod , ++a;
        	}
        	inline void output() {
        		if (a) printf("%lld%018lld
    " , a , b);
        		else printf("%lld
    " , b);
        	}
        	inline int val(int P) {
        		return (a * (mod % P) + b) % P;
        	}
        } ans;
         
        int main() {
        	 
        	 scanf("%d" , &N);
        	 for (int i = 1 , j = 0; i <= N; ++i) {
        	 	 scanf("%s%d" , s + i , &w[i]);
        	 	 s[i] = (s[i] - 'a' + ans.val(26)) % 26 + 'a'; w[i] ^= ans.val(M) & (M - 1);
        		 anc[i - 1] = s[fail[i - 1] + 1] == s[i] ? anc[fail[i - 1]] : fail[i - 1];
        		 while (j && s[j + 1] != s[i]) j = fail[j];
        	 	 if (i > 1 && s[j + 1] == s[i]) ++j;
        		 fail[i] = j;
        		 for (int now = i - 1 , val; now;)
        		 	 if (s[now + 1] == s[i]) now = anc[now];
        		 	 else val = w[*lower_bound(st + 1 , st + top + 1 , i - now)] , (--cnt[val] == 0) ? cnt.erase(val) : 0 , res -= val , now = fail[now];
        		 while (top && w[st[top]] > w[i]) --top;
        		 st[++top] = i;
        		 if (s[i] == s[1]) ++cnt[w[i]] , res += w[i];
        		 for (auto it = cnt.upper_bound(w[i]) , nxt = it; it != cnt.end(); ++it , cnt.erase(nxt) , nxt = it)
        		 	cnt[w[i]] += it -> second , res -= 1ll * it -> second * (it -> first - w[i]);
        		 ans += res; ans.output();	 
        	 }
             return 0;
        }
    
        #include <bits/stdc++.h>
         
        using namespace std;
         
        typedef long long LL;
         
        const int MN = 21;
         
        int N , Log[1 << MN] , chk[1 << MN] , f[1 << MN] , siz[1 << MN];
        LL A[MN] , sum[1 << MN];
         
        inline void chkmax(int &x , int y) {
        	x = max(x , y);
        }
         
        int main() {
        	
        	scanf("%d" , &N);
        	for (int i = 0; i < N; ++i) {
        		scanf("%lld" , &A[i]); Log[1 << i] = i;
        		if (!A[i]) --i , --N;
        	}
        	for (int i = 1; i < (1 << N); ++i)
        		sum[i] = sum[i ^ (i & (-i))] + A[Log[i & (-i)]];
        	for (int i = 0; i < (1 << N); ++i) {
        		siz[i] = siz[i >> 1] + (i & 1);
        		if (siz[i] == 1) continue;
        		for (int j = (i - 1) & i; (2 * j >= i) && j; j = (j - 1) & i)
        			if (abs(sum[j] - sum[i ^ j]) < siz[i] && ((abs(sum[j] - sum[i ^ j]) & 1) != (siz[i] & 1))) {
        				chk[i] = true;
        				break;
        			}
        	}
        	for (int s = 1; s < (1 << N); ++s) {
        		if (chk[s]) {
        			int k = ((1 << N) - 1) ^ s; f[s] = max(f[s] , 1);
        			for (int t = k; t; t = (t - 1) & k) chkmax(f[s | t] , f[t] + 1);
        		}
        	}
        	int ans = 0;
        	for (int s = 0; s < (1 << N); ++s) chkmax(ans , f[s]);
        	printf("%d
    " , N - ans);
        	return 0;
        }
    
  • 相关阅读:
    JS动态添加事件
    Asp.Net验证控件浅析
    word 文档如何加密
    scp 自动带密码参数复制文件到主机
    Zabbix监控Dell服务器相关硬件资源
    Zabbix的history相关数据表数据太大,执行表分区操作过程
    mysql日常操作
    linux下利用tcpdump抓包工具排查nginx获取客户端真实IP实例
    解决ssh登录很慢的问题以及jumpserver登录主机出现:Authentication timeout
    keepalived启动后报错:(VI_1): received an invalid passwd!的解决办法
  • 原文地址:https://www.cnblogs.com/evenbao/p/14509286.html
Copyright © 2020-2023  润新知