Codeforces Round #672 (Div. 2)

A. Cubes Sorting

题意:

能否通过 n ∗ ( n − 1 ) 2 − 1 \frac{n*(n-1)}{2}-1 2n(n1)1 次操作使得序列不降。
看到 n ∗ ( n − 1 ) 2 − 1 \frac{n*(n-1)}{2}-1 2n(n1)1 就明白了,只要不是递减序列都可以变成的。

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 main()
{
    sd(t);
    while (t--)
    {
        bool flag = true;
        sd(n);
        rep(i, 1, n)
            sd(a[i]);
        rep(i, 1, n - 1)
        {
            if (a[i] <= a[i + 1])
            {
                flag = false;
                break;
            }
        }
        if (flag)
            puts("NO");
        else
            puts("YES");
    }
    return 0;
}

B. Rock and Lever

题意:

给你一个数组,求出 i < j i < j i<j 时, a i & a j ≥ a i ⊕ a j a_i\&a_j \ge a_i \oplus a_j ai&ajaiaj成立情况的总数。

很明显的规律当最高位一样时这一对就是满足的只要统计出来最高位一样的有几个即可。

AC代码:
const int N = 2e5 + 10;
int t;
int n, m, k;
int a[N], b[N], cnt[N];
bool vis[N];
ll base[N];
 
int main()
{
    sd(t);
    base[0] = 1;
    base[1] = 2;
    rep(i, 2, 32)
        base[i] = base[i - 1] * 2;
    while (t--)
    {
        rep(i, 0, 40)
            cnt[i] = 0;
        sd(n);
        int pos = 0;
        ll ans = 0;
        rep(i, 1, n)
        {
            sd(a[i]);
            rep(j, 0, 31)
            {
                if (a[i] >= base[j] && a[i] < base[j + 1])
                {
                    pos = j;
                }
            }
            ans += cnt[pos];
            cnt[pos]++;
        }
        pld(ans);
    }
    return 0;
}

C1. Pokémon Army (easy version)

题意:

给你一个整数数组 a a a,其中每个元素代表对应神奇宝贝的力量,现在要求你选择 k k k 个索引组成的数组 b b b,其中 b 1 < b 2 < b 3 . . . b_1<b_2<b_3... b1<b2<b3...,使得 a b 1 − a b 2 + a b 3 . . . a_{b_1}-a_{b_2}+a_{b3}... ab1ab2+ab3... 最大。请你求出最大值。

d p [ i ] [ 0 ] dp[i][0] dp[i][0]为前i个数选择了偶数个数的最大和
d p [ i ] [ 1 ] dp[i][1] dp[i][1]为前i个数选择了奇数个数的最大和。

AC代码:
const int N = 3e5 + 10;
int t;
int n, m, k, q;
ll a[N], b[N], cnt[N];
bool vis[N];
ll dp[N][2];
 
int main()
{
    sd(t);
    while (t--)
    {
        sdd(n, q);
        rep(i, 0, n)
        {
            dp[i][0] = 0;
            dp[i][1] = 0;
        }
        rep(i, 1, n)
            sld(a[i]);
        rep(i, 1, n)
        {
            dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + a[i]);
            dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] - a[i]);
        }
        pld(max(dp[n][0],dp[n][1]));
    }
    return 0;
}

C2. Pokémon Army (hard version)

题意:

具体做法参考这篇博客:点击这里

AC代码:
int t;
int n, m, k, q;
ll a[N], b[N];
bool vis[N];
ll dp[N][2];
//dp[i][0]为前i个数选择了偶数个数的最大和
//dp[i][1]为前i个数选择了奇数个数的最大和。
int main()
{
    sd(t);
    while (t--)
    {
        sdd(n, q);
        rep(i, 0, n)
        {
            dp[i][0] = 0;
            dp[i][1] = 0;
        }
        rep(i, 1, n)
            sld(a[i]);
        a[n + 1] = 0;
        ll ans = 0;
        per(i, n, 1)
            b[i] = a[i] - a[i + 1];
        rep(i, 1, n)
        {
            if (b[i] > 0)
                ans += b[i];
        }
        pld(ans);
        rep(i, 1, q)
        {
            int l, r;
            sdd(l, r);
            if (l > r)
                swap(l, r);
            rep(j, max(1, l - 1), min(n, l + 1))
            {
                if (b[j] > 0)
                    ans -= b[j];
            }
            rep(j,max(l + 2, r - 1),min(n,r + 1))
            {
                if (b[j] > 0)
                    ans -= b[j];
            }
            swap(a[l], a[r]);
            rep(j,max(1, l - 1),min(n, l + 1))
            {
                b[j] = a[j] - a[j + 1];
            }
            rep(j,max(l + 2, r - 1),min(n, r + 1))
            {
                b[j] = a[j] - a[j + 1];
            }
            rep(j,max(1, l - 1),min(n, l + 1))
            {
                if (b[j] > 0)   
                    ans += b[j];
            }
            rep(j,max(l + 2, r - 1),min(n, r + 1))
            {
                if (b[j] > 0)
                    ans += b[j];
            }
            pld(ans);
        }
    }
    return 0;
}

D. Rescue Nibel!

题意:

n n n 栈灯 ,每栈灯在 [ l , r ] [ l , r] [l,r] 时间段内是开着的 ,现在需要选择 k k k 栈灯 ,使他们能在同一时间内打开 ,问有多少种选择方法 。

先按左端点排序,然后对于对于每个区间段,寻找之前有多少个区间右端点值大于当前区间段左端点值。意思是在选择当前区间段的前提下,有多少种方式在前面找 k − 1 k-1 k1 个区间与当前区间有交集。

AC代码:
const int N = 3e5 + 10;
const int mod = 998244353;

int n, k;
int c[N * 5];
map<int, int> mp;
vector<int> v;

struct Node
{
    int l, r;
} a[N];

int cmp(Node a, Node b)
{
    return a.l == b.l ? a.r < b.r : a.l < b.l;
}

void add(int x, int v)
{
    while (x <= n * 5)
    {
        c[x] += v;
        x += x & -x;
    }
}

int sum(int x)
{
    int res = 0;
    while (x)
    {
        res += c[x];
        x -= x & -x;
    }
    return res;
}

ll fac[N], inv[N];

ll C(ll n, ll m)
{
    if (m > n || m < 0)
        return 0;
    return fac[n] * ((inv[n - m] * inv[m]) % mod) % mod;
}

void init()
{
    fac[0] = 1;
    inv[0] = 1;
    for (int i = 1; i <= N - 2; i++)
    {
        fac[i] = (fac[i - 1] * i) % mod;
        inv[i] = qpow(fac[i], mod - 2, mod);
    }
}

int main()
{
    init();
    sdd(n, k);
    mp.clear();
    v.clear();
    rep(i, 1, n * 5)
        c[i] = 0;
    rep(i, 1, n)
    {
        sdd(a[i].l, a[i].r);
        v.pb(a[i].l);
        v.pb(a[i].r);
        v.pb(a[i].l - 1);
        v.pb(a[i].r - 1);
    }
    sort(a + 1, a + 1 + n, cmp);
    sort(v.begin(), v.end());
    int cnt = 0;
    rep(i, 0, v.size() - 1)
    {
        if (!mp[v[i]])
            mp[v[i]] = ++cnt;
    }
    ll ans = 0;
    rep(i, 1, n)
    {
        int num = sum(n * 5) - sum(mp[a[i].l - 1]);
        if (num >= k - 1)
        {
            ans += C(num, k - 1);
            ans %= mod;
        }
        add(mp[a[i].r], 1);
    }
    pld(ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值