传送门
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| ∣x2−x1∣+∣y2−y1∣;若两个方向距离都大于 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=(l−p2)/w−p2 用优先队列维护 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+1−l。答案为 ∑ r = 0 n − 1 f ( 0 , r ) \sum\limits_{r=0}^{n-1}f(0,r) r=0∑n−1f(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;
}