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\)

接着考虑困难版。

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

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

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

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

子串个数 \(\binom{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} \neq 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\n" , 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\n");
    			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\n");
    	 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 << "\n";
        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 << "\n";
            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 << "\n";
        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\n" , 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\n" , a , b);
    		else printf("%lld\n" , 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" , N - ans);
    	return 0;
    }
posted @ 2021-03-10 06:23  evenbao  阅读(83)  评论(0编辑  收藏  举报