Codeforces Round #673 (Div. 2)

A. Copy-paste

题意:

给你一个数组和一个限定值 k k k,你可以进行法术使得:
1 ≤ i , j ≤ n 1≤i,j≤n 1i,jn a n d and and i ≠ j i ≠ j i=j a j : = a j + a i a_j := a_j + a_i aj:=aj+ai

当进行法术操作使得其中有一个元素超过限定值 k k k 时,你都将失去该法术能力,即法术无效。问你最多能使用多少次法术。

直接看最小的可以加几次。

AC代码:
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int t;
int n, m, k;
int a[N], b[N], ans[N];
bool vis[N];
int res;
 
int main()
{
    sd(t);
    while (t--)
    {
        sdd(n, k);
        ll ans = 0;
        rep(i, 1, n)
            sd(a[i]);
        sort(a + 1, a + 1 + n);
        int minn = a[1];
        rep(i, 2, n)
        {
            res = (k - a[i]) / minn;
            ans += res;
        }
        pld(ans);
    }
    return 0;
}

B. Two Arrays

题意:

给你一个数组 a a a 和不幸值 T T T,要求你将数组 a a a 分成数组 b b b和数组 c c c,使得 f ( b ) + f ( c ) f ( b ) + f ( c ) f(b)+f(c)最小。
其中 f ( b ) f ( b ) f(b) 的值为数组 b b b 1 ≤ i < j ≤ m 1 ≤ i < j ≤ m 1i<jm 使得 a i + a j = T a_i+a_j=T ai+aj=T 的数量对数。

对于等于 T / 2 T/2 T/2 的单独处理交叉放置,大于 T / 2 T/2 T/2 的放一组,小于 T / 2 T/2 T/2 的放一组。

AC代码:
const int N = 2e5 + 10;
const int mod = 998244353;
 
int n, m, k, T;
int a[N], ans[N];
 
int main()
{
    int t;
    sd(t);
    while (t--)
    {
        sdd(n, T);
        int cnt = 0;
        rep(i, 1, n)
        {
            sd(a[i]);
            if (T % 2 == 0 && a[i] == T / 2)
            {
                cnt++;
                if (cnt & 1)
                    ans[i] = 1;
                else
                    ans[i] = 0;
            }
            else if (a[i] * 2 < T)
                ans[i] = 0;
            else
                ans[i] = 1;
        }
        rep(i, 1, n)
            printf("%d%c", ans[i], i == n ? '\n' : ' ');
    }
    return 0;
}

C. k-Amazing Numbers

题意:

这道题的题意很难理解。

给你两个数 n , k n,k nk ,求从 1   n 1~n 1 n 之间的每一个 i i i 在长度为 n n n 的数组中的,所有连续的长度为i的数组的公共最小值,如果没有重复值则输出 − 1 -1 1

遍历求每个相同的数之间的距离,即求出i到达几时这些数成为公共值,然后遍历所有求得的公共值,输出最小值即可。

AC代码:
const int N = 3e5 + 10;
const int mod = 998244353;
 
int n, m, k, T;
int a[N], ans[N];
vector<int> v[N];
int main()
{
    int t;
    sd(t);
    while (t--)
    {
        sd(n);
        rep(i, 0, n)
        {
            ans[i] = inf;
            v[i].clear();
        }
        rep(i, 1, n)
        {
            sd(a[i]);
            v[a[i]].pb(i);
        }
        rep(i, 1, n)
        {
            if (!v[i].empty())
            {
                int res = 0;
                rep(j, 1, v[i].size() - 1)
                    res = max(res, v[i][j] - v[i][j - 1]); //相同数最大的距离
                res = max(res, v[i].front());
                res = max(res, n - v[i].back() + 1);
                ans[res] = min(ans[res], i);
            }
        }
        rep(i, 2, n)
            ans[i] = min(ans[i], ans[i - 1]);
        rep(i, 1, n)
        {
            if (ans[i] < inf)
                printf("%d ", ans[i]);
            else
                printf("-1 ");
        }
        printf("\n");
    }
    return 0;
}

D. Make Them Equal

题意:

给出最大为 3 ∗ n 3*n 3n,所以可以考虑扫三次序列。最后一次应该是把通过一个数把全部数字变成平均数。那么前两次应该是收集到一个数字上。

先把所有值搞到 a 1 a_1 a1 上,最多需要 2 ( n − 1 ) 2(n-1) 2(n1) 次操作:如果 a i % i = 0 a_i\%i=0 ai%i=0 一次操作就可以否则需要先用 a 1 a_1 a1去把 a i a_i ai调整成 i i i 的倍数,然后再需要一次操作。
然后直接用 a 1 a_1 a1 把所有值搞成平均数即可最多 n − 1 n-1 n1次操作。

AC代码:
const int N = 2e5 + 10;
const int mod = 998244353;
 
int n, m, k;
int a[N];
 
int main()
{
    int t;
    sd(t);
    while (t--)
    {
        sd(n);
        ll sum = 0;
        int cnt = 0;
        rep(i, 1, n)
        {
            sd(a[i]);
            sum += a[i];
            if (a[i] % i != 0)
                cnt++;
        }
        if (sum % n != 0)
        {
            puts("-1");
            continue;
        }
        int ave = sum / n;
        pd(2 * (n - 1) + cnt);
        rep(i, 2, n)
        {
            if (a[i] % i == 0)
            {
                printf("%d 1 %d\n", i, a[i] / i); //能整除先都加到a[1]上
            }
            else
            {
                printf("1 %d %d\n", i, i - a[i] % i); //不能整除的话先从a[1]加上
                printf("%d 1 %d\n", i, a[i] / i + 1); //在减去,因为并没有实际的加上所以这里需要+1操作
            }
        }
        rep(i, 2, n)
        {
            printf("1 %d %d\n", i, ave);
        }
    }
    return 0;
}

E. XOR Inverse

题意:

给一个数组 ,需要找到一个 X X X ,使数组中每个数 异或 X X X 后 ,数组中的逆序对数最少 ,如果有多个 X X X 找最小的那个,求 X X X 和逆序对数。

字典树

AC代码:
const int N = 4e6 + 10;
const int mod = 998244353;
 
int n, m, k;
int a[N];
int tot = 1, tire[N][3];
ll dp[40][3];
ll ans1, ans2;
vector<int> v[N];
 
void insert(int x, int pos)
{
    int p = 0, t;
    for (int i = 30; i >= 0; i--)
    {
        t = (x >> i) & 1;
        if (tire[p][t] == 0)
            tire[p][t] = tot++;
        p = tire[p][t];
        v[p].push_back(pos);
    }
}
 
void dfs(int p, int pos)
{
    if (pos == -1)
        return;
    int l = tire[p][0], r = tire[p][1];
    ll sz0 = v[l].size(), sz1 = v[r].size();
    ll ans = 0, temp = 0;
    rep(i, 0, sz0 - 1)
    {
        if (!sz1)
            break;
        while (temp < sz1 && v[r][temp] < v[l][i])
            temp++;
        ans += temp;
    }
    dp[pos][0] += ans;
    dp[pos][1] += sz1 * sz0 - ans;
    if (l != 0)
        dfs(l, pos - 1);
    if (r != 0)
        dfs(r, pos - 1);
}
 
int main()
{
    int t;
    sd(n);
    rep(i, 1, n)
    {
        sd(a[i]);
        insert(a[i], i);
    }
    dfs(0, 30);
    rep(i, 0, 30)
    {
        if (dp[i][0] <= dp[i][1])
        {
            ans1 += dp[i][0];
        }
        else
        {
            ans1 += dp[i][1];
            ans2 += (1 << i);
        }
    }
    pldd(ans1, ans2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值