Codeforces Round 757 (Div. 2) 解題報告
\(\rm Codeforces ~ Round ~ 757 ~ (Div. 2)\)
A Divan and a Store
有 \(n\) 個物品,第 \(i\) 個商品的價格為 \(a_i\)。
給你 \(l\) 和 \(r\),表示商人只會選擇價格在 \([l,r]\) 內的物品。
商人有 \(k\) 元錢,問你商人最多可以買多少個商品。
共 \(T\) 組資料。
對於 \(100\%\) 的資料,保證 \(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\)
sol
貪心,每次買剩下的價格最小的商品。
首先選出滿足條件的物品,放到優先佇列裡(最小值優先)。
然後一件一件彈出來,計算錢數,若錢數 \(> k\) 或佇列為空,結束程式。
時間複雜度 \(\mathcal O(Tn \log n)\)。
#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\) 棟樓,每棟樓座標為 \(x_i\),滿足 \(\forall j \ne i,x_i \ne x_j\) 且 \(x_i\) 是一個整數。
將所有樓從 \(0\) 到 \(n\) 標號。
有一人在編號為 \(0\) 的樓,分別要去編號為 \(i\) 的建築 \(a_i\) 次,這個人往返編號為 \(i\) 的建築一趟花費的時間為 \(2 \times(|x_i - x_0|)\)。
請安排每一棟樓的座標,使得這個人花費的時間最短。
共 \(T\) 組資料。
對於 \(100\%\) 的資料,保證 \(1\leq T \leq 10^3,1 \leq n \leq 2*10^5,0 \leq a_i \leq 10^6\)
sol
首先,我們把編號為 \(0\) 的樓的座標定為 \(0\) 方便去做。
記答案為 \(ans\),則 \(ans=\sum\limits_{i=1}^{n}{2*a_i*|x_0-x_i|}\)。
要使得 \(ans\) 最少,就要讓 \(a_i\) 大的樓放到距離 \(x_0\) 近的地方。
那麼按照 \(a_i\) 從大到小排序,在 \(x_0\) 按照左右左右左右…的順序放樓即可。
具體實現見程式碼。
時間複雜度 \(\mathcal 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\),現知道 \(m\) 個資訊,每個星資訊為 l r x
的形式給出,表示區間 \([l,r]\) 的按位或為 \(x\),保證 \(a\) 中每一個數都被包含在區間 \([l,r]\) 至少一次。
請輸出序列 \(a\) 的所有子序列的異或和 \(\bmod (10^9+7)\)。
共 \(T\) 組資料。
對於 \(100\%\) 的資料,保證 \(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\)。
sol
顯然,我們可以得到整個序列的按位或就是所有 \(x\) 的按位或,設為 \(S\)。
如果 \(S\) 的第 \(i\) 位為 \(0\),貢獻即為 \(0\)。
否則總有一個 \(1\),當中恰有一個對應貢獻為 \(2^{i}\),總貢獻為 \(2^{i}\times2^{n-1}\)。
那麼 \(Ans=S \times 2^{n-1}\)。
時間複雜度 \(\mathcal 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\),使得
\[\sum\limits_{i=1}^n \gcd(a_1,a_2,...,a_i) \]最大。
輸出這個最大值。
sol
顯然,一道 dp
。
設 \(cnt_i\) 表示陣列 \(a\) 中是 \(i\) 的倍數的元素個數,\(dp_i\) 表示時能得到已含有因數 \(i\) 結尾排列能獲得的最大值。
此時有轉移方程
\[dp_i=\max_{j=1}{f_{i \times pri_j} + i \times (cnt_i - cnt_{i \times pri_j})} \]最後答案為滿足 \(cnt_i=n\) 的 \(dp_i\) 的最大值。
求 \(cnt\) 可先篩出所有質數,再列舉 \(i\) 和質數集 \(pri\),計算 \(cnt_i\)。
時間複雜度 \(\mathcal O(w \log \log 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;
}
本文來自部落格園,作者:蒟蒻orz,轉載請註明原文連結:https://www.cnblogs.com/orzz/p/15614936.html