Educational Codeforces Round 138 (Rated for Div. 2) A - D

Educational Codeforces Round 138 (Rated for Div. 2) A - D

不会D要惩罚一下自己,比如明天吃午饭少加一个蛋。。。

进入正题:


A. Cowardly Rooks 签到

题意:

在n*n的棋盘中放置一些棋子,保证这些棋盘上每一列和每一排都存在小于等于1个棋子,请问能否将一个棋子换到另一个位置同样满足要求。

分析:

根据n皇后问题的结论发现棋子最多放n个,我们只需要观察防止的棋子是否是n个即可。

代码:

void solve()
{
    cin >> n >> m;
    for(int i = 1 ; i <= m ; i ++ ) {
        cin >> x[i] >> y[i];
    }
    
    if(m < n) {
        puts("YES");
    } else if(n == m) puts("NO");
}

B. Death's Blessing 贪心

题意:

有n个怪物,怪物的属性有血量a[i]和亡语b[i],亡语会使与他相邻的怪物各增加b[i]的血量上限,杀死一个怪物的时间等于怪物的血量,请计算最快杀死所有怪物的时间。

分析:

贪心可以发现,一直杀最左边和最右边的怪物是最优的,因为他们的亡语只会触发一边,然后最后留下亡语效果最大的怪,他的亡语不会触发。

代码:

void solve()
{
    cin >> n;
    int res = 0, sum = 0, mx = 0;
    for(int i = 1 ; i <= n ; i ++ ) cin >> a[i], res += a[i];
    for(int i = 1 ; i <= n ; i ++ ) cin >> b[i], mx = max(mx, b[i]), sum += b[i];
    cout << sum + res - mx << endl;
}

C. Number Game 二分 + 贪心

题意:

有n个数,Alice和Bob玩游戏。游戏进行k轮,每一轮Alice必须消除一个小于等于 k - i + 1 的数,在消除之后,如果数组还有元素的话Bob需要对一个数增加 k - i + 1 ,求Alice在保证自己在k轮内都能消除数的前提下,最多进行的轮次。

分析:

已知的结论是:Bob增加的数从此以后不可能被Alice删掉。因此Bob肯定会贪心的删掉最小的数,而Alice希望把小数放后面消除,因此他会删除能够消除的最大的数,二分k然后线性求一遍即可。

代码:

bool check(int mid) {
    int s = 1;
    int p = n;
    for(int i = 1; i <= 100 ; i ++ ) st[i] = 0;
    for(int i = 1; i <= n ; i ++ ) {
        if(!st[i] && a[i] <= mid - s + 1) {
            s ++ ;
            st[p -- ] = true;
        }
    }
    return s > mid;
}

void solve()
{
    cin >> n;
    for(int i = 1; i <= n ; i ++ ) cin >> a[i];
    sort(a + 1, a + n + 1);
    reverse(a + 1, a + n + 1);
    int l = 0, r = (n + 1) / 2;
    while(l < r) {
        int mid = l + r + 1 >> 1;
        if(check(mid)) l = mid;
        else r = mid - 1;
    }
    cout << r << endl;
}

D. Counting Arrays 思维 + 数论

题意:

给定一个n和m,构造出一个长度为n,每一个元素的范围是[1, m]的数组,求有多少个数组是模棱两可的。一个模棱两可的数组的定义是其删除数组b不唯一,一个元素a[i]可以被删除当且仅当gcd(a[i], i) == 1。

分析:

对于每一个数组来说,一定存在这样一个删除数组b = [1,1,1,1...],那么我们只需要找出可以不按这么删的数组即可。但是一个删除数组不唯一的数组的数量很多,因此我们需要找到删除数组唯一的数组的数量,对于某一个位置a[i],a[i]和i的gcd必须>1,如果他前面的数被删掉了,那么a[i]和i - 1的gcd必须也>1... 因此对于一个a[i],他必须和从1 - i里所有的质数的倍数,假设lc是从1 - i的所有质数的乘积,那么m / lc就是他能取的数量。我们根据乘法原理统计一下即可。

sum是所有情况的方案,non是该数组的删除数组唯一的方案,答案是两者相减。

代码:

// long long 自己开
void init() {
    for(int i = 2 ; i < N ; i ++ ) {
        if(!st[i]) primes[cnt ++ ] = i;
        for(int j = 0; primes[j] * i < N ; j ++ ) {
            st[primes[j] * i] = true;
            if(i % primes[j] == 0) break;
        }
    }
}

int lcm(int a, int b) {
    return a * b / __gcd(a, b);
}

void solve()
{
    cin >> n >> m;
    int lc = 1;
    non[1] = m % mod;
    for (int i = 2; i <= n; i++) {
        if (!st[i]) lc = lcm(lc, i);
        int cnt = m / lc;
        non[i] = non[i - 1] * (cnt % mod) % mod;
    }
 
    sum[1] = m % mod;
    for (int i = 2; i <= n; i++) {
        sum[i] = sum[i - 1] * (m % mod) % mod;
    }
 
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        ans = (ans + sum[i] - non[i]) % mod;
    }
 
    cout << (ans + mod) % mod;
}

发布于 2022-10-21 01:27