Educational Codeforces Round 74 (Div. 2)

A. Prime Subtraction

题解:
所有素数都可以用2和3相加得到,所以这里只有在差值为1的时候不行
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    int T;
    cin >> T;
    while (T--) {
        ll x, y;
        cin >> x >> y;
        ll res = x - y;
        if (res == 1) cout << "NO" << endl;
        else cout << "YES" << endl;
    }

    return 0;
}

B - Kill `Em All

题解:
因为爆炸后除了爆炸点外会把其他点往外挤,所以肯定是从最远的点开始爆破
所以排序一遍,然后去重(位于同一点一起炸了)计算即可
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;

int T, N, r;
int a[MAX];
 
int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--) {
        cin >> N >> r;
        for (int i = 1; i <= N; i++) cin >> a[i];
        sort(a + 1, a + 1 + N);
        int tot = unique(a + 1, a + 1 + N) - a - 1, cnt = 0;
        for (int i = tot; i >= 1; i--)
            if (a[i] - cnt * r > 0) cnt++;//如果当前点在0右端,那就炸掉
        cout << cnt << endl;
    }
 
    return 0;
}

C - Standard Free2play

题解:
首先,若当前位于平台 p i p_i pi上,下一个平台 p i + 1 p_{i+1} pi+1,则可以通过直接改变相邻两个平台的状态到达 p i + 1 + 1 p_{i+1}+1 pi+1+1的高度
所以对于某一平台 p k p_k pk,我们一定可以到达 p k + 1 p_{k}+1 pk+1,下面有两种情况
p k + 1 = p k − 1 p_{k+1}=p_{k}-1 pk+1=pk1,显然,我们直接变换 p i p_i pi p k + 1 p_k+1 pk+1的状态就可到达 p k − 1 p_{k}-1 pk1平台,因为高度差为2,刚好不会摔死
p k + 1 < p k − 1 p_{k+1}<p_{k}-1 pk+1<pk1,也就是高度差大于2,那么如果中间没有平台,会摔死,所以这里我们需要买魔法项链将 p k − 1 p_{k}-1 pk1的平台延伸出来,花费加一
不断重复这个过程即可
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
 
int T, H, N;
int a[MAX];

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> T;
    while (T--) {
        cin >> H >> N;
        
        for (int i = 1; i <= N; i++) cin >> a[i];
 
        int cnt = 0;
        a[N + 1] = 0;//在最后加一个0平台
        for (int i = 2; i <= N; i++)
            if (a[i] - a[i + 1] >= 2) cnt++;//如果不加0平台,如果最后的a[N]会有影响
            else i++;
 
        cout << cnt << endl;
    }
 
    return 0;
}

D - AB-string

题解:
可以发现,只有2种类型的子串不符合要求
①连续的一串 A A A+ B B B,如 A A A A A B AAAAAB AAAAAB(AB可互换)
A A A+连续的一串 B B B,如 A B B B B B ABBBBB ABBBBB
所以可以统计不符合要求的子串
代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long			ll;
const int MAX = 3e5 + 10;
 
int N;
char s[MAX];
 
int main() {
    scanf("%d%s", &N, s + 1);
    ll ans = 1ll * N * (N - 1) / 2;//子串总数
    int pre = 1;//上一个连续的字符所在位置
    for (int i = 1; i <= N - 1; i++) {//正着扫一遍
        if (s[i] != s[i + 1])//遇到两个不一样的
            ans -= i + 1 - pre, pre = i + 1;
    }
    pre = N;
    for (int i = N; i >= 2; i--) {//反着扫一遍
        if (s[i] != s[i - 1])
            ans -= pre - i, pre = i - 1;//这里ans本来是减掉pre - (i - 1)
            //但是这样会重复减掉一遍AB,因为之前正着扫的时候已经减掉
    }
    cout << ans << endl;
 
    return 0;
}

E - Keyboard Purchase(状压DP)

题解:
f [ i ] f[i] f[i]为已经安装的键状态为 i i i的情况下,移动距离之和的最小值
v [ i ] [ j ] v[i][j] v[i][j]为 从键盘上的 i i i转移到 j j j的次数

如果当次安装 j j j键,并且键盘上已经有 k − 1 k-1 k1个键已经安上去,那么未安装 m − k m-k mk个键 与 已安装 k k k个键 之间的距离就多了1

不妨记, c n t cnt cnt为 未安装的键 与 已安装的键 经过增加一个键之后 增加的转移距离

那么就有了状态转移方程
f [ i ] = min ⁡ j = 1 m ( f [ i ] , f [ i ⊕ ( 1 < < j ) ] + c n t ) f[i] = \displaystyle\min_{j=1}^m(f[i],f[i⊕(1<<j)]+cnt) f[i]=j=1minm(f[i],f[i(1<<j)]+cnt)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;

int N, M;
char s[MAX];
int v[25][25], f[1 << 20];

int main() {
    scanf("%d%d%s", &N, &M, s + 1);
    for (int i = 1; i <= N - 1; i++) {
        int x = s[i] - 'a', y = s[i + 1] - 'a';
        v[x][y]++, v[y][x]++;
    }
    memset(f, 0x3f, sz(f));
    f[0] = 0;
    int mx = (1 << M) - 1;
    for (int i = 0; i <= mx; i++) {

        int cnt = 0;//计算当次贡献
        for (int j = 0; j < M; j++)
            for (int k = j + 1; k < M; k++)
                if ((i >> j & 1) ^ (i >> k & 1))//已安装 和 未安装 之间的距离加1
                    cnt += v[j][k];

        for (int j = 0; j < M; j++)
            if (i >> j & 1)//属于该状态
                f[i] = min(f[i], f[i ^ (1 << j)] + cnt);
    }
    cout << f[mx] << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值