鱼香rose'Blog

Codeforces Round 969 (Div

\(\Huge{Codeforces Round 969 (Div. 2)}\)

比赛地址:Codeforces Round 969 (Div. 2)

A. Dora's Set

题意

给出区间\([l,r]\),每次可以执行以下操作:

  • 任选三个不同的数字\(a,b,c\),使得\(gcd(a,b)=gcd(b,c)=gcd(c,a)=1\)。然后删掉\(a,b,c\)

求最多可以执行多少次操作?

思路

跟据题意,每次操作需要选三个数字,且三个数字间两两互质。那么我们只需要知道以下两个性质即可:

  • 相邻两个数字互质。
  • 相邻两个奇数互质。

那么本题就显而易见了,找到区间[l,r]中所有连续的\(a_i,a_{i+1},a_{i+2}\),且\(a_i\)为奇数即可。

标程

void Solved() { 
    int a, b; cin >> a >> b;
    if(!(a & 1)) a ++;
    int res = 0, i;
    for(i = a; i + 2 <= b; i += 4 ) {
        res ++;
    }

    cout << res << endl;
}

B. Index and Maximum Value

题意

给出一个长度为\(n\)的数组,然后执行m次操作,给出两种操作:

  • + l r:给出两个整数\(l,r\),对于数组中所有\(l \leq a_i \leq r\),令\(a_i=a_i+1\)
  • - l r:给出两个整数\(l,r\),对于数组中所有\(l \leq a_i \leq r\),令\(a_i=a_i-1\)

找出m次操作后数组中的最大值。

思路

容易想到,结果要求数组最大值。上面两种操作不会对数组的大小顺序产生影响,即原最大值在m次操作后依然是最大值。

标程

void Solved() { 
    int n, m; cin >> n >> m;

    vector<int> a(n);
    int res = 0;
    for(auto &i : a) cin >> i, res = max(res, i);

    while(m -- ) {
        char ch;
        int l, r; cin >> ch >> l >> r;
        if(res >= l && res <= r) {
            res += (ch == '+' ? 1 : -1);
        }
    
        cout << res << ' ';
    }
    cout << endl;
}

C. Dora and C++

题意

给出一个长度为\(n\)的数组,然后给出两个数字a,b,然后可以选择执行以下两种操作任意次:

  • 选择数组中的一个数字a_i,然后a_i+=a。
  • 选择数组中的一个数字a_i,然后a_i+=b。

操作可以执行任意次,最终需要最小化数组中最大、最小值的差值。

思路

很容易想到,我们可以通过将每个数字都加上若干a和若干b,使得所有数字间的差值最小。那么我们该如何操作呢?

跟据裴蜀定理,

裴蜀定理内容:

对任何整数\(a,b\)和它们的最大公约数\(d\),关于未知数\(x,y\)的线性不定方程(称为裴蜀等式):若\(a,b\)是整数,且\(gcd(a,b)=d\),那么对于任意的整数都\(x,y,ax+by\)一定是\(d\)的倍数,特别地,一定存在整数\(x,y\),使\(ax+by=d\)成立。 ——百度百科

简化为:

\[\left\{\begin{matrix} 任意x,y→gcd(a,b)|ax+by \\ax+by=gcd(a,b)有整数解 \end{matrix}\right. \]

因此,对于任意两个相等整数\(x=y\),我们可以分别加上若干a和若干b,使得\(x=y\pm p\times gcd(a,b)\),那么对于两个不相等整数\(x,y\),我们依然可以通过若干次操作使得其差值增大或减小\(p\times gcd(a,b)\),其中,\(p\)为任意整数。

那么利用该性质,本题结果必然会小于\(gcd(a,b)\),我们只需要将数组中的每个数对\(gcd(a,b)\)取模即可,同时需要排序,然后取\(min\)操作:\(min(f[i-1]+c-f[i],f[i]-f[i-1])\)即可。

标程

#define int long long 
void Solved() { 
    int n, a, b; cin >> n >> a >> b;
    int c = gcd(a, b);
    
    vector<int> f(n);
    for(auto &i : f) cin >> i, i %= c;

    sort(ALL(f));
    int res = f[n - 1] - f[0];

    for(int i = 1; i < n; i ++ ) {
        res = min(res, f[i - 1] + c - f[i]);
    }    
    
    cout << res << endl;
}

D. Iris and game on the Tree

题意

给出一棵树,树上每个节点都有三种状态:0、1、?。对于某叶子节点,根据其构造一个字符串:从根节点到该节点路径上的所有节点的状态。在该字符串上,所有1001子字符串个数的差值即为该叶子节点的权重。

树的分数定义为树中非零权重的叶子数。

现在Alice和Bob交替将节点状态中的“?”改为“0”或“1”,Alice先手,且希望最大化树的分数,Bob希望最小化树的分数。

当“?”被修改完时游戏结束,求最终树的得分?

思路

通过观察可以发现,一条从根到叶子的路径是否有得分,只取决于根节点与叶子节点是否相同。相同则无贡献,不同则有贡献。
那么双方博弈就只用看根节点和叶子的情况,先手抢占有利的一方即可。
只有一种特殊情况下需要考虑到路径节点上的“?”,即当根节点为“?”,且叶子节点中“0”,“1”的数量相等时(也可以都为0),此时双方处于平衡状态,在根节点和叶子节点上先手的一方反而会成为后手,所以Alice需要利用中间路径上的”?”来拉扯一下,如果中间路径上的“?”数量为奇数,那么通过拉扯就可以使先后手转换,那么Bob就不会亏掉这一分。

标程

void Solved() { 
    int n; cin >> n;
    vector<vector<int>> g(n + 1);
    for(int i = 1; i < n; i ++ ) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    string s; cin >> s;
    int s0 = 0, s1 = 0, a = 0;
    int b = count(s.brgin(), s.end(), '?');

    for(int i = 2; i <= n; i ++ ) {
        if(g[i].size() != 1) continue;	//只判断叶子节点
        
        if(s[i - 1] == '0') s0 ++;
        else if(s[i - 1] == '1') s1 ++;
        else a ++;
    }
    
    int res = 0;
    //判断根节点
    if(s[0] == '0') res = s1;
    else if(s[0] == '1') res = s0;
    else {
        res = max(s0, s1);
        if(s0 == s1 && (b - a - 1) % 2 == 1 && (b - a - 1) > 0) {
            a ++;
        }
        a --;
    }
    res += (a + 1) / 2;
    cout << res << endl;
}
posted @ 2026-01-15 21:47  鱼香_rose  阅读(0)  评论(0)    收藏  举报