Codeforces Raif Round 1 (Div. 1 + Div. 2)

传送门

Codeforces Raif Round 1 (Div. 1 + Div. 2)

A

考虑单一方向,则需要时间 ∣ x 2 − x 1 ∣ + ∣ y 2 − y 1 ∣ |x_2-x_1|+|y_2-y_1| x2x1+y2y1;若两个方向距离都大于 0 0 0,则需要额外 2 2 2 单位的时间改变方向。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100005

int main()
{
    int t, x1, y1, x2, y2;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        int d1 = abs(x1 - x2), d2 = abs(y1 - y2);
        printf("%d\n", d1 + d2 + (d1 > 0 && d2 > 0 ? 2 : 0));
    }
    return 0;
}
B

若节点左右侧一边为 ′ − ′ '-' ,则满足条件;若节点两侧不为 ′ − ′ '-' 且方向不同则必然不满足条件;若节点两侧不为 ′ − ′ '-' 且同方向,那必须环其余位置连通才能保证连通,此时环中至多只有一个非 ′ − ′ '-' 的方向。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 300005
char S[maxn];

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%d", &n);
        scanf("%s", S);
        int n1 = 0, n2 = 0;
        bool left = 0, right = 0;
        for (int i = 0; i < n; i++)
        {
            int j = i - 1;
            if (j < 0)
                j += n;
            if (S[i] == '<')
                left = 1;
            else if (S[i] == '>')
                right = 1;
            if (S[i] == '-' || S[j] == '-')
            {
            }
            else if ((S[i] == '<' && S[j] == '>') || (S[i] == '>' && S[j] == '<'))
            {
                ++n1;
            }
            else
            {
                ++n2;
            }
        }
        bool f = n1 || (left && right);
        printf("%d\n", n - n1 - (f ? n2 : 0));
    }
    return 0;
}
C

目标是消去最多的 ′ A B ′ , ′ B B ′ 'AB','BB' AB,BB,模式都是 ′ ∗ B ′ '*B' B,那么从后向前遍历,尽量用 B B B 匹配即可。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 200005
char S[maxn];

int main()
{
    int t, n;
    scanf("%d", &t);
    while (t--)
    {
        scanf("%s", S);
        n = strlen(S);
        int cnt = 0, res = 0;
        for (int i = n - 1; i >= 0; i--)
        {
            if (S[i] == 'B')
            {
                ++cnt;
            }
            else
            {
                if (cnt > 0)
                {
                    --cnt;
                }
                else
                {
                    ++res;
                }
            }
        }
        printf("%d\n", res + (cnt & 1));
    }
    return 0;
}
D 补题

a i = 0 a_i=0 ai=0,则不考虑此列; a i = 1 a_i=1 ai=1,则在此列放置一个点; a i = 2 a_i=2 ai=2,则需要满足此列的某一行左侧有且仅有一个点,满足 a i = 1 a_i=1 ai=1 的情况; a i = 3 a_i=3 ai=3,则它的左侧对应点所在列满足 a i = 1 , a i = 2 , a i = 3 a_i=1,a_i=2,a_i=3 ai=1,ai=2,ai=3 的情况。构造的点满足条件,则从左上角不重复的赋值各点。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define maxn 100005
int N, A[maxn], match2[maxn], match3[maxn];
bool used[maxn];
vector<int> P1, P2, P3;
vector<pair<int, int>> res;

void solve()
{
    for (int i = N; i; --i)
    {
        if (A[i] == 1)
        {
            P1.push_back(i);
        }
        else if (A[i] == 2)
        {
            if (P1.size() > 0)
            {
                match2[i] = P1.back();
                P1.pop_back();
            }
            else
            {
                puts("-1");
                return;
            }
            P2.push_back(i);
        }
        else if (A[i] == 3)
        {
            if (P3.size() > 0)
            {
                match3[i] = P3.back();
            }
            else if (P2.size() > 0)
            {
                match3[i] = P2.back();
            }
            else if (P1.size() > 0)
            {
                match3[i] = P1.back();
                P1.pop_back();
            }
            else
            {
                puts("-1");
                return;
            }
            P3.push_back(i);
        }
    }
    for (int r = 1, c = 1; c <= N; ++c)
    {
        if (used[c] || !A[c])
            continue;
        if (A[c] == 1)
        {
            res.emplace_back(r, c);
            ++r;
        }
        else if (A[c] == 2)
        {
            res.emplace_back(r, c);
            int c2 = match2[c];
            res.emplace_back(r, c2);
            used[c2] = 1, ++r;
        }
        else if (A[c] == 3)
        {
            res.emplace_back(r, c);
            int c2 = match3[c];
            res.emplace_back(r, c2);
            ++r;
        }
    }
    printf("%d\n", (int)res.size());
    for (auto p : res)
    {
        printf("%d %d\n", p.first, p.second);
    }
}

int main()
{
    scanf("%d", &N);
    for (int i = 1; i <= N; ++i)
        scanf("%d", A + i);
    solve();
}
E 补题

可以证明,当长度为 l l l 的胡萝卜分割为 p p p 份时,分割为 p 1 p1 p1 份长度为 w w w 以及 p 2 p2 p2 份长度为 w + 1 w+1 w+1 的分割方法最优,此时耗时设为 f ( l , p ) f(l,p) f(l,p)。那么有 w = ⌊ l / p ⌋ , p 2 = l   m o d   p , p 1 = ( l − p 2 ) / w − p 2 w=\lfloor l/p\rfloor,p2=l\ mod\ p, p1=(l-p2)/w-p2 w=l/p,p2=l mod p,p1=(lp2)/wp2 用优先队列维护 f ( l , p ) − f ( l , p + 1 ) f(l,p)-f(l,p+1) f(l,p)f(l,p+1),此差值对于同一根胡萝卜随着 p p p 增大而递减,故每次只用将已切割的当前值的差值入队;每次分割贪心地取最大差值。

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
#define maxn 1000005
typedef long long ll;
struct node
{
    int l, p;
    ll dif;
    bool operator<(const node &b) const
    {
        return dif < b.dif;
    }
};
int N, K, A[maxn];

ll f(ll l, ll p)
{
    if (p >= l)
        return l;
    ll w = l / p, p2 = l % p, p1 = (l - p2) / w - p2;
    return p1 * w * w + p2 * (w + 1) * (w + 1);
}

int main()
{
    scanf("%d%d", &N, &K);
    for (int i = 0; i < N; ++i)
        scanf("%d", A + i);
    ll res = 0;
    priority_queue<node> q;
    for (int i = 0; i < N; ++i)
    {
        res += 1LL * A[i] * A[i];
        q.push(node{A[i], 1, f(A[i], 1) - f(A[i], 2)});
    }
    int cut = K - N;
    for (int i = 0; i < cut; ++i)
    {
        node t = q.top();
        q.pop();
        res -= t.dif;
        ++t.p;
        t.dif = f(t.l, t.p) - f(t.l, t.p + 1);
        q.push(t);
    }
    printf("%lld\n", res);
    return 0;
}
F 补题

固定 r r r 考虑 f ( l , r ) f(l,r) f(l,r),则其随着 l l l 减小非严格递增。对于 f ( l , r + 1 ) f(l,r+1) f(l,r+1),若 s r + 1 = 0 s_{r+1}=0 sr+1=0,则有 f ( l , r ) = f ( l , r + 1 ) f(l,r)=f(l,r+1) f(l,r)=f(l,r+1);若 s r + 1 = 1 s_{r+1}=1 sr+1=1,设当前位置左侧有连续的 h h h 1 1 1,设使 f ( l , r ) = h f(l,r)=h f(l,r)=h 的最大位置为 l l l,即这 h h h 1 1 1 能影响到的最远位置,则有 f ( l , r + 1 ) = f ( l , r ) + r + 1 − l f(l,r+1)=f(l,r)+r+1-l f(l,r+1)=f(l,r)+r+1l。答案为 ∑ r = 0 n − 1 f ( 0 , r ) \sum\limits_{r=0}^{n-1}f(0,r) r=0n1f(0,r)

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define inf 0x3f3f3f3f
#define maxn 500005
typedef long long ll;
int N;
ll rec[maxn];
char S[maxn];

int main()
{
    scanf("%d", &N);
    scanf(" %s", S);
    memset(rec, -1, sizeof(rec));
    ll sum = 0, f = 0;
    for (int i = 0; i < N; ++i)
    {
        if (S[i] == '0')
            sum += f;
        else
        {
            int l = i, r = i;
            while (r < N && S[r + 1] == '1')
                ++r;
            for (int j = l; j <= r; ++j)
            {
                int h = j - l + 1;
                f += j - rec[h];
                sum += f;
            }
            for (int j = r; j >= l; --j)
            {
                int h = r - j + 1;
                rec[h] = j;
            }
            i = r;
        }
    }
    printf("%lld\n", sum);
    return 0;
}
G1 补题
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值