Educational Codeforces Round 86 個人題解
1342A - Road To Zero(簡單分類討論)
題意:給兩個整數 和 ,需要把這兩個數都變成 ,現在有 和 兩個操作,其中 操作花費 的代價將其中一個數字 或者 , 操作花費 的代價將兩個數字同時 或者 ,問最小的代價是多少,需要回答 個案例。
範圍:
題解:
顯然對 和 兩個數字都進行一次 操作,其效果等價於進行了一次 操作,如果 則 操作完全可以被 操作取代,否則就需要進行 次 操作消除兩數的差異再進行 次 操作。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 2e5;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n;
signed main()
{
int T = read();
while (T--)
{
int x, y, a, b;
cin >> x >> y >> a >> b;
if (x > y)
swap(x, y);
if (2 * a <= b)
{
cout << a * (x + y) << endl;
}
else
{
cout << b * x + a * (y - x) << endl;
}
}
return 0;
}
1342B - Binary Period(構造)
題意:給一個 串 ,需要找到一個長度不超過 的 串 滿足: 是 的子序列且 擁有最小的循環長度。只需要給出一個滿足條件的 ,需要回答 個案例。
範圍:
題解:
不要求最優解,考慮找一下規律。可以發現如果 中只包含 或者只包含 ,那麼 也只需要包含 或者只包含 ,循環長度爲 ;如果 中既有 也有 ,那麼 可以構造成以 爲最小循環子串的長度爲 的 串,循環長度爲 ,這樣對於 中的每一位都可以在一個 循環子串中匹配到。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 2e5;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n;
signed main()
{
int T = read();
while (T--)
{
string str;
cin >> str;
int cnt1 = 0, cnt2 = 0;
for (int i = 0; i < str.length(); i++)
{
if (str[i] == '0')
cnt1++;
else
cnt2++;
}
string ans = "";
// 只有1
if (cnt1 == 0)
{
for (int i = 0; i < 2 * str.length(); i++)
{
ans += '1';
}
}
// 只有0
else if (cnt2 == 0)
{
for (int i = 0; i < 2 * str.length(); i++)
{
ans += '0';
}
}
// 兩個都有
else
{
for (int i = 0; i < str.length(); i++)
{
ans += '0';
ans += '1';
}
}
cout << ans << endl;
}
return 0;
}
1342C - Yet Another Counting Problem(數學+前綴和)
題意:有 個案例,每個案例給兩個整數 和 ,以及 個詢問,每個詢問給出 和 ,需要計算在區間 中有多少個數字 滿足 。
範圍:
題解:
可以發現對於給定的 和 ,從小到大滿足條件的 以一個週期進行循環,而這個週期就是 和 的公倍數,每個週期內滿足條件的 數量相同。顯然 是 和 的公倍數,且 ,那麼我們就可以預處理出一個週期內滿足條件 的前綴和,因此就可以對所有的查詢區間 進行前綴和差分求解,。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 4e4 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int a, b, q;
int dp[MAXN];
int calc(int x)
{
// 有x/(a*b)個完整週期,還剩下一個x%(a*b)的週期
return dp[a * b] * (x / (a * b)) + dp[x % (a * b)];
}
signed main()
{
int T = read();
while (T--)
{
memset(dp, 0, sizeof(dp));
cin >> a >> b >> q;
// 預處理前綴和
dp[0] = 0;
for (int i = 1; i <= a * b; i++)
{
if (i % a % b == i % b % a)
dp[i] = dp[i - 1];
else
dp[i] = dp[i - 1] + 1;
}
for (int i = 0; i < q; i++)
{
int x, y;
cin >> x >> y;
// 前綴差分
cout << calc(y) - calc(x - 1) << endl;
}
}
return 0;
}
1342D - Multiple Testcases(二分)
題意:有 個數字 ,並且有一種容器,一個容器只能存放 個 的數字, 個 的數字,…, 個 的數字,問至少需要多少個容器才能裝下所有數字。
範圍:
題解:
考慮到數據範圍,我們不能夠對每個容器的各個檔位去找數字存放,也不能對於每個數字直接遍歷去找哪個容器還可以存放,不過可以利用二分進行優化遍歷的過程。
首先我們對數字進行排序,從大到小的進行處理,對於每個數字需要找到哪個容器可以容納下該數字,而進行遍歷的效率太低。
基於貪心的想法,一個容器需要儘可能多的存放數字,實在沒辦法了才使用新的容器,那麼最後每個容器中的數字數量會呈現遞減的形式,對於這樣的一個序列我們可以使用二分進行快速查找。
由於最多隻會使用 個容器,那麼我們可以建立一個數組 保存每個容器中數字的數量。對於當前需要插入的數字 ,進行二分找到第一個 的位置進行插入,該容器至少還剩下 個位置可以存放 的數字,將 加入該容器中即可。
詳見代碼。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n, k;
int m[MAXN], cap[MAXN], num[MAXN];
vector<int> vec[MAXN];
signed main()
{
n = read(), k = read();
for (int i = 0; i < n; i++)
{
int x = read();
m[x]++; // m[x]表示數字x的數量
}
for (int i = 1; i <= k; i++)
{
cap[i] = read();
}
// maxV用來保存容器的數量
int maxV = 0;
// 從後往前遍歷
for (int i = k; i >= 1; i--)
{
// 處理m[i]個數字i
while (m[i])
{
// 二分找到第一個num<c[i]的容器
int l = 0, r = MAXN;
int ans;
while (l <= r)
{
int mid = l + r >> 1;
if (num[mid] < cap[i])
{
ans = mid;
r = mid - 1;
}
else
{
l = mid + 1;
}
}
// 更新容器數量
maxV = max(maxV, ans);
// 更新該容器大小
num[ans]++;
// 減少一個數字i
m[i]--;
// 將數字i加入容器ans中
vec[ans].push_back(i);
}
}
// 輸出答案
cout << maxV + 1 << endl;
for (int i = 0; i <= maxV; i++)
{
cout << vec[i].size();
for (auto x : vec[i])
{
cout << " " << x;
}
cout << endl;
}
return 0;
}
【END】感謝觀看!