比赛链接
牛客练习赛130
A题
思路
如果 x x x和 y y y相等,一步都不需要。
将 x x x和 y y y进行二进制拆位,如果同时出现 x x x的二进制位等于 1 1 1并且 y y y的二进制位等于 0 0 0和 x x x的二进制位等于 0 0 0并且 y y y的二进制位等于 1 1 1,则至少需要2步。
否则,1步即可。
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
int x, y;
void solve()
{
cin >> x >> y;
if (x == y)
{
cout << 0 << endl;
return;
}
int cnt1 = 0, cnt2 = 0;
for (int i = 60; i >= 0; i--)
{
int bit = (x >> i) & 1;
int op = (y >> i) & 1;
if (bit == 1 && op == 0)
{
cnt1++;
}
if (bit == 0 && op == 1)
{
cnt2++;
}
}
if (cnt1 && cnt2)
{
cout << 2 << endl;
return;
}
cout << 1 << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
B题
思路
当 h + R ∗ ( k − 1 ) < = 0 h + R * (k - 1) <= 0 h+R∗(k−1)<=0或 h + k ∗ L > 0 h + k * L > 0 h+k∗L>0时,必然无解,否则一定有解。
我们可以先令前 k − 1 k-1 k−1个为 R R R,第 k k k个为 L L L。令 s u m = h + R ∗ ( k − 1 ) + L sum = h + R * (k - 1) + L sum=h+R∗(k−1)+L,如果 s u m > 0 sum > 0 sum>0,则说明骑士的血多了。
我们可以倒着进行调整,如果当前的 a n s [ i ] ans[i] ans[i]可以继续调整,则用 a n s [ i ] 减去 ans[i]减去 ans[i]减去 m i n ( s u m , R − L ) min(sum,R-L) min(sum,R−L)。
代码
#pragma GCC optimize("O2")
#pragma GCC optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> pii;
const int N = 2e5 + 5, M = 1e6 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, k, h, L, R;
void solve()
{
cin >> n >> k >> h >> L >> R;
if (h + R * (k - 1) <= 0 || h + k * L > 0)
{
cout << "impossible" << endl;
return;
}
vector<int> ans(n + 1, 0);
for (int i = 1; i < k; i++)
ans[i] = R;
ans[k] = L;
int sum = h + R * (k - 1) + L;
for (int i = k - 1; i >= 1; i--)
{
if (sum <= 0)
break;
int op = min(sum, R - L);
ans[i] -= op;
sum -= op;
}
for (int i = k + 1; i <= n; i++)
ans[i] = L;
for (int i = 1; i <= n; i++)
{
cout << ans[i] << " ";
}
cout << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}
C题
思路
当 i ≤ j i \le j i≤j时, V = ∑ i = 1 n ∑ j = 1 n f i × g j V = \sum_{i=1}^{n} \sum_{j=1}^{n}f_{i} \times g_{j} V=∑i=1n∑j=1nfi×gj。
当 i ≥ j i \ge j i≥j时, V = ∑ i = 1 n ∑ j = 1 n f j × g i V = \sum_{i=1}^{n} \sum_{j=1}^{n}f_{j} \times g_{i} V=∑i=1n∑j=1nfj×gi。
因此, V = ∑ i = 1 n ∑ j = i n f i × g j + ∑ i = 1 n ∑ j = 1 i f j × g i − ∑ i = 1 n f i × g i V = \sum_{i=1}^{n} \sum_{j=i}^{n}f_{i} \times g_{j} + \sum_{i=1}^{n} \sum_{j=1}^{i}f_{j} \times g_{i} - \sum_{i=1}^{n}f_{i}\times g_{i} V=∑i=1n∑j=infi×gj+∑i=1n∑j=1ifj×gi−∑i=1nfi×gi。
化简得: V = ∑ i = 1 n f i × ( ∑ j = i n g j ) + ∑ i = 1 n g i × ( ∑ j = 1 i f j ) − ∑ i = 1 n f i × g i V = \sum_{i=1}^{n}f_{i} \times (\sum_{j=i}^{n}g_{j}) + \sum_{i=1}^{n}g_{i} \times (\sum_{j=1}^{i}f_{j}) - \sum_{i=1}^{n}f_{i}\times g_{i} V=∑i=1nfi×(∑j=ingj)+∑i=1ngi×(∑j=1ifj)−∑i=1nfi×gi。
令 p r e [ ] pre[] pre[]为 f [ ] f[] f[]的前缀和数组, n x t [ ] nxt[] nxt[]为 g [ ] g[] g[]的后缀和数组。
则 V = ∑ i = 1 n f i × n x t [ i ] + ∑ i = 1 n g i × p r e [ i ] − ∑ i = 1 n f i × g i V = \sum_{i=1}^{n}f_{i} \times nxt[i] + \sum_{i=1}^{n}g_{i} \times pre[i] - \sum_{i=1}^{n}f_{i}\times g_{i} V=∑i=1nfi×nxt[i]+∑i=1ngi×pre[i]−∑i=1nfi×gi。
因此,我们可以用两棵线段树分别维护 p r e [ ] pre[] pre[]和 n x t [ ] nxt[] nxt[]的区间和,每以此询问即是一次单点修改和区间查询。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 5, M = 1e6 + 5;
const int mod = 998244353;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, q;
int f[N], g[N], pre[N], nxt[N];
struct segmenttree
{
struct node
{
int l, r, sum, tag;
};
vector<node> tree;
segmenttree() : tree(1) {}
segmenttree(int n) : tree(n * 4 + 1) {}
void pushup(int u)
{
auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
root.sum = (left.sum + right.sum) % mod;
}
void pushdown(int u)
{
auto &root = tree[u], &left = tree[u << 1], &right = tree[u << 1 | 1];
if (root.tag != 0)
{
left.tag += root.tag;
left.tag %= mod;
right.tag += root.tag;
right.tag %= mod;
left.sum += ((left.r - left.l + 1) * root.tag % mod);
left.sum %= mod;
right.sum += ((right.r - right.l + 1) * root.tag % mod);
right.sum %= mod;
root.tag = 0;
}
}
void build(int u, int l, int r, int w[])
{
auto &root = tree[u];
root = {l, r};
if (l == r)
{
root.sum = w[r] % mod;
}
else
{
int mid = l + r >> 1;
build(u << 1, l, mid, w);
build(u << 1 | 1, mid + 1, r, w);
pushup(u);
}
}
void modify(int u, int l, int r, int val)
{
auto &root = tree[u];
if (root.l >= l && root.r <= r)
{
root.sum += ((tree[u].r - tree[u].l + 1) * val % mod);
root.sum %= mod;
root.tag += val;
root.tag %= mod;
return;
}
pushdown(u);
int mid = root.l + root.r >> 1;
if (l <= mid)
modify(u << 1, l, r, val);
if (r > mid)
modify(u << 1 | 1, l, r, val);
pushup(u);
}
int query(int u, int l, int r)
{
auto &root = tree[u];
if (root.l >= l && root.r <= r)
{
return root.sum % mod;
}
pushdown(u);
int mid = root.l + root.r >> 1;
int res = 0;
if (l <= mid)
res += query(u << 1, l, r), res %= mod;
if (r > mid)
res += query(u << 1 | 1, l, r), res %= mod;
return res;
}
};
int MOD(int x)
{
return (x % mod + mod) % mod;
}
void solve()
{
cin >> n >> q;
for (int i = 1; i <= n; i++)
{
cin >> f[i];
}
for (int i = 1; i <= n; i++)
{
cin >> g[i];
}
for (int i = 1, j = n; i <= n; i++, j--)
{
pre[i] = (pre[i - 1] + f[i]) % mod;
nxt[j] = (nxt[j + 1] + g[j]) % mod;
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
ans = (ans + (f[i] * nxt[i]) % mod) % mod;
ans = (ans + (g[i] * pre[i]) % mod) % mod;
ans = (ans - f[i] * g[i] % mod) % mod;
}
ans = MOD(ans);
segmenttree smt1(n);
segmenttree smt2(n);
smt1.build(1, 1, n, pre);
smt2.build(1, 1, n, nxt);
while (q--)
{
int t, i, x;
cin >> t >> i >> x;
if (t == 1)
{
smt1.modify(1, i, n, -f[i]);
ans = (ans - f[i] * smt2.query(1, i, i) % mod) % mod;
int res = 0;
res = smt2.query(1, i, i);
ans = (ans - res * (f[i] % mod) % mod) % mod;
ans = (ans + f[i] * g[i] % mod) % mod;
f[i] = x;
smt1.modify(1, i, n, f[i]);
ans = (ans + f[i] * smt2.query(1, i, i) % mod) % mod;
ans = (ans + res * (f[i] % mod) % mod) % mod;
ans = (ans - f[i] * g[i] % mod) % mod;
}
else
{
smt2.modify(1, 1, i, -g[i]);
ans = (ans - g[i] * smt1.query(1, i, i) % mod) % mod;
int res = 0;
res = smt1.query(1, i, i);
ans = (ans - res * g[i] % mod) % mod;
ans = (ans + f[i] * g[i] % mod) % mod;
g[i] = x;
smt2.modify(1, 1, i, g[i]);
ans = (ans + g[i] * smt1.query(1, i, i) % mod) % mod;
ans = (ans + res * g[i] % mod) % mod;
ans = (ans - f[i] * g[i] % mod) % mod;
}
ans = MOD(ans);
cout << ans << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int test = 1;
// cin >> test;
for (int i = 1; i <= test; i++)
{
solve();
}
return 0;
}