C o d e f o r c e s R o u n d 757 ( D i v . 2 ) \rm Codeforces ~ Round ~ 757 ~ (Div. 2) Codeforces Round 757 (Div.2)
A Divan and a Store
有 n n n 个物品,第 i i i 个商品的价格为 a i a_i ai。
给你 l l l 和 r r r,表示商人只会选择价格在 [ l , r ] [l,r] [l,r] 内的物品。
商人有 k k k 元钱,问你商人最多可以买多少个商品。
共 T T T 组数据。
对于 100 % 100\% 100% 的数据,保证 1 ≤ T ≤ 100 , 1 ≤ n ≤ 100 , 1 ≤ l ≤ r ≤ 1 0 9 , 1 l e q k ≤ 1 0 9 , 1 ≤ a i ≤ 1 0 9 1\leq T \leq 100,1 \leq n \leq 100,1 \leq l \leq r \leq 10^9,1 \ leq k \leq 10^9,1 \leq a_i \leq 10^9 1≤T≤100,1≤n≤100,1≤l≤r≤109,1 leqk≤109,1≤ai≤109。
sol
贪心,每次买剩下的价格最小的商品。
首先选出满足条件的物品,放到优先队列里(最小值优先)。
然后一件一件弹出来,计算钱数,若钱数 > k > k >k 或队列为空,结束程序。
时间复杂度 O ( T n log n ) \mathcal O(Tn \log n) O(Tnlogn)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n, l, r, k;
signed main()
{
scanf("%lld", &t);
while (t--)
{
scanf("%lld%lld%lld%lld", &n, &l, &r, &k);
priority_queue<int, vector<int>, greater<int>> q;
for (int i = 1, a; i <= n; ++i)
{
scanf("%lld", &a);
if (a < l || a > r)
continue;
q.push(a);
}
int ans = 0, sum = 0;
while (!q.empty())
{
int now = q.top();
q.pop();
sum += now;
// cout << now << "\n";
if (sum <= k)
ans++;
else
break;
}
printf("%lld\n", ans);
}
return 0;
}
B Divan and a New Project
在一条街上,盖 n + 1 n+1 n+1 栋楼,每栋楼坐标为 x i x_i xi,满足 ∀ j ≠ i , x i ≠ x j \forall j \ne i,x_i \ne x_j ∀j=i,xi=xj 且 x i x_i xi 是一个整数。
将所有楼从 0 0 0 到 n n n 标号。
有一人在编号为 0 0 0 的楼,分别要去编号为 i i i 的建筑 a i a_i ai 次,这个人往返编号为 i i i 的建筑一趟花费的时间为 2 × ( ∣ x i − x 0 ∣ ) 2 \times(|x_i - x_0|) 2×(∣xi−x0∣)。
请安排每一栋楼的坐标,使得这个人花费的时间最短。
共 T T T 组数据。
对于 100 % 100\% 100% 的数据,保证 1 ≤ T ≤ 1 0 3 , 1 ≤ n ≤ 2 ∗ 1 0 5 , 0 ≤ a i ≤ 1 0 6 1\leq T \leq 10^3,1 \leq n \leq 2*10^5,0 \leq a_i \leq 10^6 1≤T≤103,1≤n≤2∗105,0≤ai≤106。
sol
首先,我们把编号为 0 0 0 的楼的坐标定为 0 0 0 方便去做。
记答案为 a n s ans ans,则 a n s = ∑ i = 1 n 2 ∗ a i ∗ ∣ x 0 − x i ∣ ans=\sum\limits_{i=1}^{n}{2*a_i*|x_0-x_i|} ans=i=1∑n2∗ai∗∣x0−xi∣。
要使得 a n s ans ans 最少,就要让 a i a_i ai 大的楼放到距离 x 0 x_0 x0 近的地方。
那么按照 a i a_i ai 从大到小排序,在 x 0 x_0 x0 按照左右左右左右…的顺序放楼即可。
具体实现见代码。
时间复杂度 O ( T n ) \mathcal O(Tn) O(Tn)。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int _ = 2e5 + 7;
int t;
int n;
struct abc
{
int v, id;
} a[_];
int b[_];
int ans;
bool cmp(abc a, abc b)
{
return a.v > b.v;
}
signed main()
{
scanf("%lld", &t);
while (t--)
{
ans = 0;
scanf("%lld", &n);
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i].v), a[i].id = i;
sort(a + 1, a + n + 1, cmp);
int k = 0;
for (int i = 1; i <= n; i += 2)
{
b[a[i].id] = ++k;
}
k = 0;
for (int i = 2; i <= n; i += 2)
{
b[a[i].id] = --k;
}
for (int i = 1; i <= n; ++i)
{
ans += 2 * a[i].v * abs(b[a[i].id]);
}
cout << ans << "\n";
cout << "0 ";
for (int i = 1; i <= n; ++i)
cout << b[i] << " ";
cout << "\n";
}
return 0;
}
C Divan and bitwise operations
有一个未知的序列
a
a
a,现知道
m
m
m 个信息,每个星信息为 l r x
的形式给出,表示区间
[
l
,
r
]
[l,r]
[l,r] 的按位或为
x
x
x,保证
a
a
a 中每一个数都被包含在区间
[
l
,
r
]
[l,r]
[l,r] 至少一次。
请输出序列 a a a 的所有子序列的异或和 m o d ( 1 0 9 + 7 ) \bmod (10^9+7) mod(109+7)。
共 T T T 组数据。
对于 100 % 100\% 100% 的数据,保证 1 ≤ T ≤ 1 0 3 , 1 ≤ n , m ≤ 2 ∗ 1 0 5 , 1 ≤ l ≤ r ≤ n , 0 ≤ x ≤ 2 30 − 1 1\leq T \leq 10^3,1 \leq n,m \leq 2*10^5,1 \leq l \leq r \leq n,0 \leq x \leq 2^{30}-1 1≤T≤103,1≤n,m≤2∗105,1≤l≤r≤n,0≤x≤230−1。
sol
显然,我们可以得到整个序列的按位或就是所有 x x x 的按位或,设为 S S S。
如果 S S S 的第 i i i 位为 0 0 0,贡献即为 0 0 0。
否则总有一个 1 1 1,当中恰有一个对应贡献为 2 i 2^{i} 2i,总贡献为 2 i × 2 n − 1 2^{i}\times2^{n-1} 2i×2n−1。
那么 A n s = S × 2 n − 1 Ans=S \times 2^{n-1} Ans=S×2n−1。
时间复杂度 O ( T n ) \mathcal O(Tn) O(Tn)。
具体实现见代码。
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read()
{
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar())
if (c == '-')
w = -1;
for (; isdigit(c); c = getchar())
s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
const int mod = 1e9 + 7;
inline int qpow(int x, int y)
{
int res = 1;
while (y)
{
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
int T, n, m;
signed main()
{
T = read();
while (T--)
{
n = read(), m = read();
int ans = 0;
while (m--)
{
read(), read();
ans = ans | read();
}
ans = ans * qpow(2, n - 1) % mod;
printf("%lld\n", ans);
}
return 0;
}
D Divan and Kostomuksha
给定序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an,要求重排 a a a,使得
∑ i = 1 n gcd ( a 1 , a 2 , . . . , a i ) \sum\limits_{i=1}^n \gcd(a_1,a_2,...,a_i) i=1∑ngcd(a1,a2,...,ai)
最大。
输出这个最大值。
sol
显然,一道 dp
。
设 c n t i cnt_i cnti 表示数组 a a a 中是 i i i 的倍数的元素个数, d p i dp_i dpi 表示时能得到已含有因数 i i i 结尾排列能获得的最大值。
此时有转移方程
d
p
i
=
max
j
=
1
f
i
×
p
r
i
j
+
i
×
(
c
n
t
i
−
c
n
t
i
×
p
r
i
j
)
dp_i=\max_{j=1}{f_{i \times pri_j} + i \times (cnt_i - cnt_{i \times pri_j})}
dpi=j=1maxfi×prij+i×(cnti−cnti×prij)
最后答案为满足
c
n
t
i
=
n
cnt_i=n
cnti=n 的
d
p
i
dp_i
dpi 的最大值。
求 c n t cnt cnt 可先筛出所有质数,再枚举 i i i 和质数集 p r i pri pri,计算 c n t i cnt_i cnti。
时间复杂度 O ( w log log w ) \mathcal O(w \log \log w) O(wloglogw),其中 w w w 为值域。
具体实现见代码。
#include <bits/stdc++.h>
using namespace std;
#define int long long
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
{
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
const int _ = 2e7 + 1;
int n;
int ans;
int cnt[_ + 7];
int dp[_ + 7];
bool vis[_];
vector<int> primes;
void init()
{
for (int i = 2; i < _; ++i)
{
if (!vis[i])
primes.push_back(i);
for (auto p : primes)
{
if (p * i > _)
break;
vis[p * i] = 1;
if (i % p == 0)
break;
}
}
}
signed main()
{
init();
n = read();
for (int i = 1, x; i <= n; ++i)
cnt[read()]++;
for (auto p : primes)
for (int j = _ / p; j >= 1; --j)
cnt[j] += cnt[j * p];
for (int i = _ - 1; i >= 1; --i)
{
dp[i] = cnt[i] * i;
for (auto p : primes)
{
int j = p * i;
if (j > _)
break;
dp[i] = max(dp[i], dp[j] + i * (cnt[i] - cnt[j]));
}
if (cnt[i] == n)
ans = max(ans, dp[i]);
}
printf("%lld\n", ans);
return 0;
}
E Divan and a Cottage
给定 n n n 天的气温 T i T_i Ti,设第 i i i 天温度为 P P P,则第 i + 1 i+1 i+1 天的温度为:
-
P + 1 ( P < T i ) P+1 ( P < T_i) P+1(P<Ti)
-
P − 1 ( P > T i ) P-1 ( P >T_i) P−1(P>Ti)
-
P ( P = T i ) P(P = T_i) P(P=Ti)
对第 i i i 天有 k i k_i ki 个询问,问若第 0 0 0 天的温度为 x x x ,那么第 i i i 天的温度是多少。
强制在线。
sol
显然,所有初始的室温变化后的结果满足单调。
那用一棵动态开点值域线段树维护所有初始的室温变化后的结果即可。
具体地,每次插入一个气温 T i T_i Ti 后,在线段树上二分以得到变化后的室温为 T i T_i Ti 的区间 [ l , r ] \left[l,r\right] [l,r],之后 [ − 1 , l ) [-1,l) [−1,l) 区间 + 1 +1 +1, ( r , M a x T + 1 ] \left(r,MaxT+1\right] (r,MaxT+1] 区间 − 1 -1 −1 即可。
时间复杂度 O ( n log w ) \mathcal{O}(n \log w) O(nlogw),其中 w w w 为值域。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline ll read()
{
ll x = 0, f = 1;
char c = getchar();
while ((c < '0' || c > '9') && (c != '-'))
c = getchar();
if (c == '-')
f = -1, c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + c - '0', c = getchar();
return x * f;
}
const int N = 2e5 + 10, mod = 1e9 + 1;
int n, m;
const int M = 4e7 + 10;
int tot, mn[M], mx[M], tag[M], ls[M], rs[M];
inline int New(int l, int r)
{
++tot, mn[tot] = l, mx[tot] = r;
return tot;
}
inline void upd(int u, int x)
{
mn[u] += x, mx[u] += x, tag[u] += x;
}
inline void push_down(int u, int l, int r, int mid)
{
if (!tag[u])
return;
if (!ls[u])
ls[u] = New(l, mid);
if (!rs[u])
rs[u] = New(mid + 1, r);
upd(ls[u], tag[u]), upd(rs[u], tag[u]);
tag[u] = 0;
}
inline void update(int &u, int l, int r, int ql, int qr, int x)
{
if (ql > qr)
return;
if (!u)
u = New(l, r);
if (l >= ql && r <= qr)
{
upd(u, x);
return;
}
int mid = l + r >> 1;
push_down(u, l, r, mid);
if (ql <= mid)
update(ls[u], l, mid, ql, qr, x);
if (qr > mid)
update(rs[u], mid + 1, r, ql, qr, x);
mn[u] = min(!ls[u] ? l : mn[ls[u]], !rs[u] ? mid + 1 : mn[rs[u]]);
mx[u] = max(!ls[u] ? mid : mx[ls[u]], !rs[u] ? r : mx[rs[u]]);
}
inline int Findl(int u, int l, int r, int x)
{
if ((!u ? l : mn[u]) >= x)
return -1;
if (l == r)
return l;
int mid = l + r >> 1;
push_down(u, l, r, mid);
int ret = Findl(rs[u], mid + 1, r, x);
if (ret != -1)
return ret;
return Findl(ls[u], l, mid, x);
}
inline int Findr(int u, int l, int r, int x)
{
if ((!u ? r : mx[u]) <= x)
return mod;
if (l == r)
return l;
int mid = l + r >> 1;
push_down(u, l, r, mid);
int ret = Findr(ls[u], l, mid, x);
if (ret != mod)
return ret;
return Findr(rs[u], mid + 1, r, x);
}
inline int Query(int u, int l, int r, int ql)
{
if (l == r)
return !u ? l : mn[u];
int mid = l + r >> 1;
push_down(u, l, r, mid);
if (ql <= mid)
return Query(ls[u], l, mid, ql);
return Query(rs[u], mid + 1, r, ql);
}
signed main()
{
n = read();
ll lasans = 0;
int rt = 0;
for(int i = 1; i <= n; ++i)
{
int x = read();
int l = Findl(rt, 0, 1e9, x), r = Findr(rt, 0, 1e9, x);
update(rt, 0, 1e9, 0, l, +1);
update(rt, 0, 1e9, r, 1e9, -1);
m = read();
for(int j = 1; j <= m; ++j)
{
int x = (read() + lasans) % mod;
printf("%lld\n", lasans = Query(rt, 0, 1e9, x));
}
}
}