CF1895
A
手玩一下就能出来的东西吧,粘个核心代码。
if(x > y) ww(x), wl;
else if(x + k >= y) ww(y), wl;
else ww(y * 2 - x - k), wl;
B
观察性质,一定是将数组排序后,从 \(1 \sim n\) 为横坐标,从 \(n + 1 \sim n * 2\) 为纵坐标。所得距离应为横坐标之差的和和纵坐标之差的和。
核心代码。(手玩一下也能出来。)
read(n);
sum = 0;
fos(i, 1, n * 2) read(a[i]);
sort(a + 1, a + n * 2 + 1);
fos(i, 2, n) sum += a[i] - a[i - 1];
fos(i, n + 2, n * 2) sum += a[i] - a[i - 1];
ww(sum), wl;
fos(i, 1, n) ww(a[i]), ws, ww(a[2 * n - i + 1]), wl;
C
分类讨论:
- 拼接的两段长度一样,则看这两段的数位和是不是相同,相同则统计答案。
- 前短后长,答案 \(b_{i, j}\)
- 前长后短,枚举右部长度,通过 \(num\) 数组统计答案。
核心代码
预处理大法吼啊,直接缩小复杂度。
read(n);
fos(i, 1, n)
{
read(a[i]);
cnt = 0; ll j = a[i], sum = 0;
while(j) cc[ ++ cnt] = j % 10, sum += cc[cnt], j /= 10;
++ num[cnt][sum]; ll sum2 = 0;
foa(j, 1, cnt)
{
sum2 += cc[j];
if(cnt >= j * 2 || sum2 * 2 <= sum) continue;
++ b[j * 2 - cnt][sum2 * 2 - sum];
}
}
fos(i, 1, n)
{
cnt = 0; ll j = a[i], sum = 0;
while(j) cc[ ++ cnt] = j % 10, sum += cc[cnt], j /= 10;
ans += num[cnt][sum]; ans += b[cnt][sum]; ll sum2 = 0;
for(rl j = 1; j * 2 <= cnt; ++ j)
{
sum2 += cc[j];
if(sum2 * 2 > sum) break;
ans += num[cnt - j * 2][sum - sum2 * 2];
}
}
D
你最喜欢的构造
我们看到这个给出来的式子是一个差分的形式,经过一些列的转变变成一个前缀和的样子,我们发现最后只和 \(b_1\) 有关,我们就可以枚举 \(b_1\) 的值然后求一遍这个数列能跑出来的最大异或值,检查是否小于 \(n\)。维护最大异或和自然想到 01-trie。
核心代码
#define ll long long
#define rl register ll
#define fom(i, a) for(rl i=a; i; -- i)
#define foa(i, a, b) for(rl i=a; i < b; ++ i)
#define fos(i, a, b) for(rl i=a; i <= b; ++ i)
#define fop(i, a, b) for(rl i=a; i >= b; -- i)
const ll N = 2e6 + 10;
ll n, idx, tr[2][N], a[N], s[N];
inline void insert(ll x)
{
ll p = 0;
fop(i, 30, 0)
{
bool u = x & (1 << i);
if(!tr[u][p]) tr[u][p] = ++ idx;
p = tr[u][p];
}
}
inline ll check(ll x)
{
ll p = 0, res = 0;
fop(i, 30, 0)
{
bool u = x & (1 << i);
if(tr[!u][p]) res |= (1 << i), p = tr[!u][p]; else p = tr[u][p];
}
return res;
}
int main()
{
// freopen("1.in", "r", stdin);
read(n); insert(0); foa(i, 1, n) read(a[i]); foa(i, 1, n) s[i] = s[i - 1] ^ a[i], insert(s[i]);
foa(i, 0, n) if(check(i) < n) { ww(i), ws; foa(j, 1, n) ww(i ^ s[j]), ws; return flush(), 0; }
return flush(), 0;
}
E
这个题目先考虑最优策略,一定是出出来手牌中攻击力比对面的防御力要高的手牌中的防御力最大的手牌。我们就对攻击力进行排序,然后统计最大后缀。然后进行一下记搜就好了,时间复杂度 \(O(\log n)\)。
core code
struct node
{
ll x, y, win;
bool operator <(const node &t) const { return x < t.x; }
} a[N], b[N];
ll dfs(ll u)
{
if(a[u].win != -1) return a[u].win; node o = { a[u].y, 0, 0 };
ll p = upper_bound(b + 1, b + 1 + m, o) - b; a[u].win = 1;
if(p > m) return a[u].win = 0; o = { hmm[p], 0, 0 };
ll q = upper_bound(a + 1, a + 1 + n, o) - a; if(q > n) return a[u].win = 2;
return a[u].win = dfs(hm[q]);
}
inline void solve()
{
read(n); fos(i, 1, n) read(a[i].x), a[i].win = -1; fos(i, 1, n) read(a[i].y), hm[i] = 0; hm[n + 1] = 0;
read(m); fos(i, 1, m) read(b[i].x), b[i].win = -1; fos(i, 1, m) read(b[i].y), hmm[i] = 0; hmm[m + 1] = 0;
sort(a + 1, a + 1 + n), sort(b + 1, b + 1 + m); ans[0] = ans[1] = ans[2] = 0;
fom(i, n) if(a[i].y > a[hm[i + 1]].y) hm[i] = i; else hm[i] = hm[i + 1]; fom(i, m) hmm[i] = max(hmm[i + 1], b[i].y);
fos(i, 1, n) if(a[i].win == -1) dfs(i); fos(i, 1, n) ans[a[i].win] ++ ; fos(i, 0, 2) ww(ans[i]), ws; wl;
}