Codeforces Round #789 (Div. 2) B~E

Codeforces Round #789 (Div. 2) B~F

B.Tokitsukaze and Good 01-String

链接
题意:给出01字符串,要求每次可以修改一个地方,最后要让连续的1和连续的0的长度都是偶数,输出最下操作次数和最后的段数
思路:首先考虑都变成奇数,从头开始每次跳2,假如不一样,说明出现了奇数的0或者1,就需要变成,然后统计段数,当和最后一次记录不同的时候,说明段数加一

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int T;
    cin >> T;
    while (T--) {
        int n;string s;
        cin >> n >> s;
        int ans1 = 0, ans2 = 0;
        char last = '_';
        for (int i = 0; i < n; i += 2) {
            if (s[i] != s[i + 1]) {
                ans1++;
            }else  {
                if (last != s[i]) ans2++;
                last = s[i];
            }
        }cout << ans1 << ' ' << max(1, ans2) << endl;
    }
    return 0;
}

Tokitsukaze and Strange Inequality

链接
题意:给出数组p,数组元素是 1   n 1~n 1 n的排列,要找出4个下标 a , b , c , d a,b,c,d a,b,c,d,要满足 a < b < c < d & & p a < p c a<b<c<d\&\&p_a<p_c a<b<c<d&&pa<pcand p b > p d p_b>p_d pb>pd,问可以找多少组。
思路:利用一个前缀和的思想直接处理出来每个数前面比他大的然后枚举b,c就完了

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 5050;
int cnt[N][N], a[N];
signed main()
{
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) {cin >> a[i];}
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                cnt[i][j] = cnt[i - 1][j];
            }
            for (int j = a[i]; j <= n; j++) {
                cnt[i][j]++;
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            for (int j = i + 1; j <= n; j++) {
                ans += (cnt[i - 1][a[j] - 1] * (cnt[n][a[i]] - cnt[j][a[i]]));
            }
        }cout << ans << endl;
    }
    return 0;
}

D.Tokitsukaze and Meeting

链接
题意:给出一个01字符串,然后有一个 n ∗ m n*m nm的矩阵,每次顺序往里面加入字符串的一个元素,前面的依次后移,如果一排满了则到下一排的第一个,对于每一排或者每一列,如果有1那就是一个好的排或列,问每次加入新元素后有几个好的排和列
思路:首先对于已经出现过的状态,比如0100,这时候记录他排的贡献,那么在经过了m次加入后,这个状态会再次出现,但是多了新的一排,所以我们可以定义dp数组,有 d p [ i ] = d p [ i − m ] + ( c n t ! = 0 ) dp[i] = dp[i-m]+(cnt!=0) dp[i]=dp[im]+(cnt!=0),其中cnt是第一排1的个数,而对于列,实际上我们每次都可以看成吧最后一列移到第一列然后加入一个0或者1,所以每一列最多提供1的答案,我们只要记录这一列是不是第一次出现1就行,最后的答案就是 a n s 列 + d p [ i ] ans_列+dp[i] ans+dp[i]

#include<bits/stdc++.h>
using namespace std;
int dp[1000010], r[1000010];
int n, m;
string s;
int main()
{
    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        cin >> s;
        for (int i = 0; i <= max(n,m); i++) r[i] = 0, dp[i] = 0;
        int cnt = 0;int ans = 0;
        for (int i = 0; i < n * m; i++) {

            r[i % m] += s[i] - '0';
            if ((r[i % m] == 1) && (s[i] == '1')) ans ++;
            cnt += s[i] - '0';
            if (i >= m) {
                cnt = cnt - (s[i - m] - '0');
            }
            if (i >= m) {dp[i] = dp[i - m] + (!(cnt == 0));}
            else dp[i] = (!(cnt == 0));
            cout << ans + dp[i] << ' ';
        }cout << endl;
    }
    return 0;
}

E.Tokitsukaze and Two Colorful Tapes

链接
题意:给出数组ab,他们都是 1   n 1~n 1 n的排列,可以把ab里面相同的数字变成另一个数字,最后也要是 1   n 1~n 1 n的排列,然后需要求 m a x ( ∑ i = 1 n ∣ a i − b i ∣ ) max(\sum_{i=1}^{n}|a_i-b_i|) max(i=1naibi),问max的值
思路:对于每个位置可以看成 a i a_i ai b i b_i bi连接一条边,最后会构成一个个环,我们要让最大,也就是在环内部我们要大小大小的交替出现,求和公式为 ∣ c 1 − c 2 ∣ + ∣ c 2 − c 3 ∣ . . . . ∣ c n − c 1 ∣ |c_1-c_2|+|c_2-c_3|....|c_n-c_1| c1c2+c2c3....cnc1,最后就是,一半大数一半小数,交替出现,大数一定是累加上答案,小数就是累减上答案,并查集或者dfs统计环大小。

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int N = 1e5+10;
int fa[N], siz[N], a[N], b[N];
int find(int n) {return n == fa[n] ? n : fa[n] = find(fa[n]);}
signed main()
{
    int T;
    cin >> T;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++) fa[i] = i, siz[i] = 1;
        for (int i = 1; i <= n; i++) cin >> a[i];
        for (int i = 1; i <= n; i++) cin >> b[i];
        for (int i = 1; i <= n; i++) {
            int x = a[i], y = b[i];
            x = find(x), y = find(y);
            if (x == y) continue;
            fa[x] = y;
            siz[y] += siz[x];
        }int idx = 0;
        for (int i = 1; i <= n; i++) {
            if (fa[i] == i) {
               idx += siz[i] / 2;
            }
        }
        int ans = 0;
        for (int i = 1; i <= idx; i++) {
            ans -= i;
        }
        for (int i = n - idx + 1; i <= n; i++) {
            ans += i;
        }
        cout << ans * 2 << endl;
    }
    return 0;
}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值