zoukankan      html  css  js  c++  java
  • CF1464C Poman Numbers

    CF1464C Poman Numbers

    Codeforces, Codeforces Round #692 (Div. 1, based on Technocup 2021 Elimination Round 3), CF#692, CF1464C Poman Numbers

    题目大意

    题目链接

    对一个由小写字母组成的非空字符串 (S),定义它可以对应的数值 (f(S))

    • 如果 (|S| > 1),则可以任选一个 (1leq m < |S|),并令 (f(S) = -f(S[1,m]) + f(S[m + 1, |S|]))
    • 否则设 (S) 里唯一的字符为 (c),则 (f(S) = 2^{ ext{pos}(c)})。其中 ( ext{pos}(c)) 表示字符 (c) 在字母表中的位置,( ext{pos}( exttt{a}) = 0, ext{pos}( exttt{z}) = 25)

    每一步里的 (m) 可以独立选择。

    给你一个长度为 (n) 的字符串 (S),和一个整数 (T)。请你判断 (f(S)) 是否可能等于 (T)

    数据范围:(1leq nleq 10^5)(-10^{15}leq Tleq 10^{15})

    本题题解

    考虑 (f(S[1,n])) 递归的过程,相当于建出一棵二叉树,满足这棵二叉树恰有 (n) 个叶子,且每个非叶子节点恰有两个儿子。从左到右,每个叶子依次对应了 (S[1,n]) 里的每个字符。

    那么我们可以将 (f(S[1,n])) 的值拆成 (n) 个叶子的贡献。对每个叶子,考虑从它到根的路径,设其中有 ( ext{leftStep}) 步是向左走的,那么它最终的贡献系数就是 ((-1)^{ ext{leftStep}})

    引理一

    (S_n) 的贡献系数必须为 (1)(S_{n - 1}) 的贡献系数必须为 (-1)。除 (S_n)(S_{n - 1}) 外,其他每个叶子的贡献系数无论怎么选择,都能构造出对应的二叉树。

    证明

    设每个节点的贡献系数分别为:(c_1,c_2,dots,c_n)。((forall i: c_iin{-1,1}))。

    (S_n) 在二叉树上只能是一直向右(因为每个非叶子节点必须有两个儿子),所以贡献系数 (c_n) 一定是 (1)

    又因为 (S_{n - 1})(S_n) 的兄弟,所以它们只有最下面一步不同((n-1) 向左,(n) 向右),因此 (c_{n - 1} = -1)

    对于其他节点,考虑递归地解决。初始时 (C = {c_1,c_2,dots,c_n}) ((ngeq 2))。

    • 若当前 (c_1 = -1),则递归 (C_L = {c_1}, C_R = {c_2, c_3, dots, c_{|C|}})
    • 若当前 (c_1 = 1),则找到它后面第一个 (c_p = -1) 的位置 (p)(显然 (p < |C|))。递归 (C_L = {-c_1,-c_2,dots , -c_p}, C_R = {c_{p + 1}, dots ,c_{|c|}})。发现两个集合都仍然满足 (c_{|C|} = 1, c_{|C| - 1} = -1)

    边界是 (|C| = 1) 时,就已经自动完成了构造。

    于是问题转化为,要确定一个 (c) 序列,满足 (forall i: c_i in{-1,1}),且 (c_n = 1, c_{n - 1} = -1),使得 (sum_{i = 1}^{n}c_i 2^{ ext{pos}(S_i)} = T)

    不妨先假设 (forall 1leq ileq n - 2)(c_i = -1)。求出此时的和 ( ext{sum} = -sum_{i = 1}^{n-1}2^{ ext{pos}(S_i)} + 2^{ ext{pos}(S_n)})。这是能得到的最小值。若 (T < ext{sum}) 则一定无解。否则令 (T'= T - ext{sum})

    然后问题进一步转化为:给定 (n - 2) 个形如 (2^k) 的数 (a_1,dots,a_{n - 2}),问是否能从中选出一个子集,使得和为 (T')。其中 (1leq kleq 26),注意不是 (0)(25),因为从 (-1) 变成 (1) 相当于增大两倍。

    引理二

    对于任意整数 (Kgeq 1),如果一个可重集 (A = {a_1,a_2,dots,a_m}) 满足所有 (a_i) 形如 (2^k) ((0leq k < K)(k) 是整数),且所有数之和大于 (2^K)。那么一定存在一个子集 (Bsubset A),满足 (B) 里所有数之和等于 (2^K)

    证明

    (K = 1) 时显然正确。

    (K > 1) 时,用归纳法。假设已经对 (K - 1) 成立。考虑 (K),先把 (A) 里所有 (2^{K - 1}) 挑出来,如果有至少 (2)(2^{K - 1}),那么已经达到要求。否则用剩下的数去拼 (2^{K - 1}),根据归纳假设,一定能恰好拼出所需的数量。

    回到本题,我们从大到小考虑 (a_1,dots, a_{n - 2}) 里所有数。如果当前数 (a_i leq T'),就选择 (a_i),并令 (T') 减去 (a_i)。最终如果 (T' = 0),答案就是 ( exttt{Yes}),否则是 ( exttt{No})。根据引理二可以说明这个贪心的正确性。

    时间复杂度 (mathcal{O}(n + Sigma))(Sigma = 26)

    参考代码

    // problem: CF1464C
    #include <bits/stdc++.h>
    using namespace std;
    
    #define pb push_back
    #define mk make_pair
    #define lob lower_bound
    #define upb upper_bound
    #define fi first
    #define se second
    #define SZ(x) ((int)(x).size())
    
    typedef unsigned int uint;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int, int> pii;
    
    template<typename T> inline void ckmax(T& x, T y) { x = (y > x ? y : x); }
    template<typename T> inline void ckmin(T& x, T y) { x = (y < x ? y : x); }
    
    const int MAXN = 1e5;
    int n;
    char s[MAXN + 5];
    
    ll goal;
    int cnt[26];
    
    int main() {
    	cin >> n >> goal;
    	cin >> (s + 1);
    	goal -= (1LL << (s[n] - 'a')); // s[n] 一定是正号
    	goal += (1LL << (s[n - 1] - 'a')); //  s[n - 1] 一定是负号
    	
    	ll low = 0;
    	for (int i = 1; i <= n - 2; ++i) {
    		int c = (s[i] - 'a');
    		cnt[c]++;
    		low -= (1LL << c);
    	}
    	
    	if (goal < low) {
    		cout << "No" << endl;
    		return 0;
    	}
    	
    	goal = goal - low;
    	
    	for (int i = 25; i >= 0; --i) {
    		ll v = (1LL << (i + 1));
    		ll x = min(goal / v, (ll)cnt[i]);
    		goal -= x * v;
    	}
    	if (goal) {
    		cout << "No" << endl;
    	} else {
    		cout << "Yes" << endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    H5本地存储
    小知识(h5 js )
    在ubuntu18.04版本安装vscode
    函数基本操作
    python直接赋值、深浅拷贝实例剖析
    collections模块简介
    set()集合基本操作
    list、tuple、dict内部功能释义
    str内部方法释义
    int内部方法释义
  • 原文地址:https://www.cnblogs.com/dysyn1314/p/14183815.html
Copyright © 2011-2022 走看看