Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)

Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round)

A

题意

进行一次翻转,求相邻两数最大和

思路

总可以将最大的两个凑一起

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N;
    cin >> N;
    vector<int> a(N);
    for(int i = 0;i < N;i ++) cin >> a[i];
    sort(a.begin(),a.end());
    cout << a[N - 1] + a[N - 2] << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

B

题意

每次删除一个字符串的极长重复前缀,

重复前缀指可以在后面找到一个与它相同且不相交的子串

求删到最后剩什么

思路

如果该字母只有一个,显然不可删

考虑删除一个极长前缀,可以变成多次删一个字符的操作

所以只要这个字符串中的同类字符大于一,这个字符就是可删的

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    string s;
    cin >> s;
    vector<int> cnt(26);
    for(int i = 0;i < s.size();i ++) {
        cnt[s[i] - 'a'] ++;
    }
    int st = 0;
    for(int i = 0;i < s.size();i ++) {
        if(cnt[s[i] - 'a'] > 1) {
            cnt[s[i] - 'a'] --;
            st ++;
        }else break;
    }
    for(int i = st;i < s.size();i ++) {
        cout << s[i] ;
    }
    cout << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

C

题意

把一个数等分 $N - 1 $ 次,如果这个数是奇数,按上下取整等分

现在给出操作结果,问是否合法

思路

第一思路是开一个小根堆,每次取出最小的两个,合并它们看是否满足要求

但可以发现拆分策略不是优先合并最小值

不考虑过程,可以发现这个操作的终止状态和起始状态都十分明确

向上合并的策略不好发现,不妨向下拆分

显然最大的数字一定最先被拆出来,设当前未被拆出的最大值为 \(x\)

所以就维护大根堆,拿出队首 $ mx $ ,和 $ x $ 比较

如果 $ mx $ 较小,显然无论如何都凑不出

如果 $mx $ 和 $ x $ 相同,固定这个 \(mx\) ,不再对它拆分,更新当前 $mx $ 和 \(x\)

如果大,那无论如何都要将它继续拆分

如果拆分 \(n - 1\) 次后合法,则输出 YES。

如果发现,大的数总是先被拆出以及如果当前数大就一定要继续拆分,当前数小,就说明不再有拆出这个数的可能,就非常显然了。

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=1e9 + 7;

void solve()
{    
    int N;
    cin >> N;
    vector<int> a(N + 1);
    int sum = 0;
    for(int i = 1;i <= N;i ++) {
        cin >> a[i];
        sum += a[i];
    }
    if(N == 1) {
        cout << "YES\n";
        return;
    }
    sort(a.begin() + 1,a.end());
    
    int cnt = 0;
    priority_queue<int> q;
    q.push(sum);
    while(cnt != N) {
        int t = q.top();
        q.pop();
        if(t == a.back()) {
            a.pop_back();
            cnt ++;
        }else if(t > a.back()) {
            q.push(t / 2);
            q.push((t + 1) / 2);
            // cnt += 2;
        }else {
            cout << "NO\n";
            return;
        }
    }
    cout << "YES\n";
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);

    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}

D

题意

$ N $ 种配料,给出它们的比例,保证每种配料都受到约束,共给出 \(N - 1\) 个比例关系。

问为使得配料在满足给出比例情况下,各个配料的最小整数解的和是多少

思路

\(N - 1\) 个比例关系当成在两种配料之间的一条边,就可以构成一棵树。

显然如果我们可以得到任意配料的一个解,其他配料都可以通过比例推出

那么我们随便取这棵关系树的某一个点当根,想办法找到根节点的解,然后再推出其他节点的解把它们求和就是答案了

如何求出根根节点的解呢?

不妨设根节点的解为 \(t\)

根和它的子节点的比例是 \(x_i:y_i\)

子节点 \(v\) 的解就是 $t * \frac {y_i}{x_i} $

以此类推任意一节点的解 \(w\) 都可以写成

\[w = t * \prod \frac{y_i}{x_i} \]

为了保证 \(w\) 是一个整数, \(t\) 最小是分母的 \(lcm\)

\(lcm\) 本质上就是对每一个质因数的幂次取 \(max\) 的过程

所以我们可以动态维护每一个节点分母的质因子幂次最大值

需要注意的是,我们还需要考虑分子对质因子的影响

比如 $ \frac{3}{2} * \frac{2}{3} $ 的情况,因为分子和分母会相消,所以在维护分母质因子幂次最大值时要先将分子的质因子幂次减去

如此求出质因子幂次最大值,把它们乘起来就是 \(t\)

有了 \(t\) 答案就很显然了

#include<bits/stdc++.h>
#define yes puts("yes");
#define inf 0x3f3f3f3f
#define ll long long
#define linf 0x3f3f3f3f3f3f3f3f
#define debug(x) cout<<'>' << ' ' << x<<endl;
#define ull unsigned long long
#define endl '\n'
#define lowbit(x) x&-x
#define int long long
using namespace std;
typedef pair<int,int> PII;
const int MAXN =10 + 2e5 ,mod=998244353;
map<int,int> ps[MAXN];// 预处理出每个数的质因数与幂次
int inv[MAXN];
void init() {
    inv[0] = inv[1] = 1;
    for(int i = 2;i < MAXN;i ++) {
        inv[i] = (mod - mod / i) * inv[mod % i] % mod;
    }
    for(int i = 2;i < MAXN;i ++) {
        int now = i;
        for(int j = 2;j <= now / j;j ++) {
            while(now % j == 0) {
                now /= j;
                ps[i][j] ++;
            }
        }
        if(now != 1) ps[i][now] ++;
    }
}
int ksm(int a,int b) {
    int ans = 1;
    a %= mod;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
void solve()
{    
    int N;
    cin >> N;
    vector<tuple<int,int,int>> tr[N + 1];
    for(int i = 0;i < N - 1;i ++) {
        int u,v,x,y;
        cin >> u >> v >> x >> y;
        tr[u].push_back({v,x,y});
        tr[v].push_back({u,y,x});
    }

    vector<int> cnt(N + 1,0);
    vector<int> mxp(N + 1,0);// 全局质因子幂次最大值
    function<void(int,int)> dfs = [&](int u,int fa) {// 求t
        for(auto [v,x,y] : tr[u]) {
            if(v == fa) continue;
            for(auto [r,e] : ps[y]) {
                cnt[r] -= e;
            } 
            for(auto [r,e] : ps[x]) {
                cnt[r] += e;
                mxp[r] = max(mxp[r],cnt[r]);
            }
            
            dfs(v,u);

            for(auto [r,e] : ps[y]) {
                cnt[r] += e;
            } 
            for(auto [r,e] : ps[x]) {
                cnt[r] -= e;
            }
        }
    };
    dfs(1,1);
    
    int t = 1;
    for(int i = 1;i <= N;i ++) {
        t = (t * ksm(i,mxp[i])) % mod;
    } 

    vector<int> w(N + 1);
    w[1] = t;
    function<void(int,int)> dfs2 = [&](int u,int fa) {
        for(auto [v, x, y] : tr[u]) {
            if(v != fa) {// a : b = x : y    b = ya / x
                w[v] = w[u] * y % mod * inv[x] % mod;
                dfs2(v,u);
            }
        }
    };
    dfs2(1,1);

    int ans = 0;
    for(int i = 1;i <= N;i ++) ans = (ans + w[i]) % mod;

    cout << ans << endl;
}
signed main()
{
    ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
    init();
    int T;cin>>T;
    while(T--)
        solve();

    return 0;
}
posted @ 2022-03-21 10:30  Mxrurush  阅读(159)  评论(5编辑  收藏  举报