Codeforces Round #818 (Div. 2)

Problem A

题意:对于 ,求的总数

 

 

思路:考察gcd和lcm的定义,gcd是a,b素因子的交集,lcm是a,b素因子的并集,相当于是lcm ∩ gcd,也就是说a与b之间除了素因子w(w=1,2,3),其他的素因子相同,所以a=b*w(a>=b)

 

 

复制代码
#include<iostream>
#include<cstring>
using namespace std;
using LL = long long;

int main(){

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    int T;
    cin >> T;
    while(T--){
        int n;
        cin >> n;
        cout << n + 2 * (n / 2 + n / 3) << '\n';
    }

}
复制代码

 

Problem B

题意:一个n*n的矩形,我们需要往矩形上填充‘X’,保证每行每列至少有一个‘X’,同时n是k的倍数,我们还需要保证任意一个1*k和k*1的矩形中包含一个‘X’,另外pos(r,c)必须是‘X’,询问最少‘X’的数量。

 

思路: 1.首先我们先不考虑pos(r,c)和小矩形限制,对于任意正方形满足行列至少有一个‘X’,

    将对角线填充上‘X’就是最优解,我把他叫做对角线推论。

    2.然后考虑将n*n矩形分割为k*k矩形,对角线推论任然满足。

    3.下一步考虑加入pos(r,c),对于这种情况,为了继续满足对角线推论,这个小的子矩形我们任然按照推论填充,保证子矩形最优解。

    4.然后与这个子矩形相对的子矩形我们同样按照这个最优策略,这样就可以保证最后的结果是最优的。

            5.最后为了满足1*k和k*1的小矩形限制,只需要将对角线向两边平移即可

 

 

 

复制代码
#include<bits/stdc++.h>
using namespace std;
int t, n, k, r, c;
void solve() {
    cin >> n >> k >> r >> c;
    r--, c--;
    int dis = (r + c) % k;//实际处理对角线平移技巧,将从1开始编号的矩阵改为从0开始,如果(r+c)%k=(a+b)%k,则(a,b)处于平移对角线上
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            int _dis = (i + j) % k;
            if (_dis == dis)
                cout << "X";
            else
                cout << ".";
        }
        cout << endl;
    }
}
int main() {
    cin >> t;
    while (t--) {
        solve();
    }
}
复制代码

Problem C

题意:给出a数列和b数列,如果能将a数列变化为b数列输出“YES”,否则输出“NO”

           变换规则是  ai:=ai+1 if i<ni<n and ai≤ai+1, or i=n and ai≤a1

 

思路:比赛时已经分析出了

          1.a序列可以变为任意满足条件3的b序列

          2. ai>bi无解

          3. b序列中,|b(n)-b(n+1)|>=2则无解

   但是第三条结论有漏洞应当更正为:ai!=bi, bi>b(i+1) +1无解,因为这会导致第i位被限制到b(i+1)-1

     

           考虑一下如果要求方案该如何求

           在满足上述条件的情况下如果ai=bi,那么该位满足

           如果ai<bi,ai>aj,我们需要首先增加aj,因为ai的增加受到aj的限制

           如果ai<bi,ai<=aj,那么直接搞就好

           可以发现这跟拓扑排序十分相似,只有出现第二种情况时才会对其他的操作施加前置 限制,所以当出现第二种情况时,我们在图上连上一条j——>i的边

           同时因为我们推断出了a数列可以变化为任意满足条件3的b数列,这个图是无环的,满足拓扑排序条件

 

复制代码
#include<bits/stdc++.h>
using namespace std;
int t, n;
const int N = 2e5 + 10;
int a[N], b[N];
void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    for (int i = 1; i <= n; i++) cin >> b[i];
    bool flag = true;
    b[n + 1] = b[1];//要判断b[n]和b[1]之间的关系,但如果(i+1)=n取模需要特判,为了省事直接接一个b[1]在后面
    for (int i = 1; i <= n; i++) {
        if (a[i] > b[i]) flag = false;
        if (a[i] != b[i] && b[i] > b[i + 1] + 1) flag = false;
        if (!flag) break;
    }
    if (flag)
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
}
int main() {
    cin >> t;
    while (t--) {
        solve();
    }
}
复制代码

Problem D

题意:2^n个人两两比赛,胜者晋级并两两之间进行下一轮比赛,按照此规则决出冠军

      Madoka有修改比赛结果的权利,最后决出的冠军编号越小,他的收益就会越大;

           但是同时赞助商有着k次修改已选定比赛结果的权利,最后冠军的编号越大赞助商收益越大。

           询问双方按照各自的最优策略选择,最后的冠军编号是多少

 

思路:双方策略

      Madoka:最后的冠军编号小

      赞助商:最后的冠军编号大

      我们发现双方的目的关联性比较小,但他们其实等价于

      Madoka:使得赞助商选不到较大的冠军编号

      赞助商:最后的冠军编号大

 

       进一步的,赞助商的选定优先级是2^n, 2^(n-1), 2^(n-2)……

      所以Madoka的策略是让得到较大编号的修改次数尽可能多,最大修改次数为n次

      又因为所有的选择情况为

 

 

    

如何让一些选手不可能获胜呢?我们知道n个人中一定有n / 2个人刚开始就失败了,因此我们让编号最大的人直接失败,到下一层也是。如何选出这些人的数量呢?因为一共要进行n次比赛,我们只需要统计出某些人失败的次数 > k的人数,把这些人都用最大编号的人来排即可。

我们一遍for(int i = k + 1 ; i <= n ; i ++ )循环,每次有C(n, i)的人永远不可能胜利。

复制代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
int n, k, op;
int qpow(int x) {
    int ans = 1, q = 2;
    while (x) {
        if (x & 1)
            ans = ans * q % mod;
        q = q * q % mod;
        x >>= 1;
    }
    return min(mod, ans);
}
int C(int x, int y) {
    if (y > x / 2) y = x - y;
    int a = 1, b = 1;
    for (int i = 1; i <= y; i++) {
        a = a * (x + 1 - i) % mod;
        b = b * i % mod;
        if (a % b == 0) a /= b, b = 1;
    }
    return a / b;
}
void solve() {
    cin >> n >> k;
    op = qpow(n);
    if (k >= n) {
        cout << op;
        return;
    }
    int w = C(n, k);
    for (int i = k + 1; i <= n; i++) {
        w = w * (n - i + 1) % mod;//节约时间
        w = w / i;
        op = ((op - w) % mod + mod) % mod;
    }
    cout << op;
    return;
}
signed main() {
    std::ios::sync_with_stdio(false);//加快cin读取速度的
    cin.tie(0);
    solve();
    return 0;
}//只过了7个点
复制代码

 

 

Problem E

 

 核心思想就是: gcd(a,b)=1, a+b=c ——>gcd(a,c)=1

复制代码
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
using LL = long long;
const int maxn = 1e5 + 5, mod = 1e9 + 7;

template<int T>
struct ModInt {
    const static int mod = T;
    int x;
    ModInt(int x = 0) : x(x% mod) {}
    int val() { return x; }
    ModInt operator + (const ModInt& a) const { int x0 = x + a.x; return ModInt(x0 < mod ? x0 : x0 - mod); }
    ModInt operator - (const ModInt& a) const { int x0 = x - a.x; return ModInt(x0 < mod ? x0 + mod : x0); }
    ModInt operator * (const ModInt& a) const { return ModInt(1LL * x * a.x % mod); }
    ModInt operator / (const ModInt& a) const { return *this * a.inv(); }
    void operator += (const ModInt& a) { x += a.x; if (x >= mod) x -= mod; }
    void operator -= (const ModInt& a) { x -= a.x; if (x < 0) x += mod; }
    void operator *= (const ModInt& a) { x = 1LL * x * a.x % mod; }
    void operator /= (const ModInt& a) { *this = *this / a; }
    friend ostream& operator<<(ostream& os, const ModInt& a) { return os << a.x; }

    ModInt pow(LL n) const {
        ModInt res(1), mul(x);
        while (n) {
            if (n & 1) res *= mul;
            mul *= mul;
            n >>= 1;
        }
        return res;
    }

    ModInt inv() const {
        int a = x, b = mod, u = 1, v = 0;
        while (b) {
            int t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        if (u < 0) u += mod;
        return u;
    }

};
typedef ModInt<mod> mint;

bool isPrime[maxn];
int phi[maxn];
int primes[maxn], cnt;
void init() {
    phi[1] = 1;
    for (int i = 2; i < maxn; i++) {
        if (!isPrime[i]) primes[cnt++] = i, phi[i] = i - 1;
        for (int j = 0; i * primes[j] < maxn; j++) {
            isPrime[i * primes[j]] = 1;
            if (i % primes[j] == 0) {
                phi[i * primes[j]] = phi[i] * primes[j];
                break;
            }
            phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    }
}
LL __gcd(LL a, LL b) {
    if (b)
        return __gcd(b, a % b);
    else
        return a;
}
int main() {

    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);

    auto lcm = [&](int a, int b) {
        return mint(a / __gcd(a, b)) * mint(b);
    };

    init();
    int n;
    cin >> n;
    mint ans = 0;
    for (int i = 1; i <= n; i++)
        for (int j = 2 * i; j < n; j += i)
            ans += lcm(i, n - j) * mint(phi[j / i]);
    cout << ans << '\n';

}
复制代码

 

 

 



posted @   Aacaod  阅读(27)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示