Educational Codeforces Round 103 Editorial 補題ing
A
A. K-divisible Sum
題意:給兩個數字n,k,構造一個有n個數的陣列使得陣列的總和可以整除k,且要使這個陣列中的每個數儘可能的小,輸出陣列中的最大值。
分情況討論:
如果n >= k;
1.如果n能整除k,那麼n個數全為1即可
2.如果n不能整除k,那麼1和2也能構造成功
如果n < k;
那麼數的取值級為 k / n 的上取整
在整數上取整中,例子:ceil(k / n) = (k + n - 1) / n
程式碼:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int T, n, k;
void solve() {
cin >> n >> k;
if(n >= k) {
if(n % k == 0) cout << 1 << '\n';
else cout << 2 << '\n';
} else cout << (k + n - 1) / n << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while(T--) solve();
return 0;
}
B
題目大意:
一種產品的價格變化統計資料用n個正整數的陣列表示,
p
0
,
p
1
,
p
2
.
.
.
p
n
−
1
p_0,p_1,p_2...p_{n-1}
p0,p1,p2...pn−1,其中
p
0
p_0
p0是產品的初始價格,
p
i
p_i
pi是第i個月的價格增長情況。使用這些價格變化要求你計算每個月的通貨膨脹係數:
(
p
0
+
p
1
+
p
2
.
.
.
+
p
i
−
1
)
/
p
i
(p_0 + p_1 + p_2 ... + p_{i - 1}) / p_i
題解:
一個顯然的條件:直接增加
p
0
p_0
p0即可,因為所有的通貨膨脹係數的分母均含有
p
0
p_0
p0,因此增加
p
0
p_0
p0即可。
假設增加的值為x,那麼需要滿足該公式成立
p
i
/
(
p
0
+
p
1
+
p
2
+
.
.
.
+
p
i
−
1
+
x
)
<
=
k
/
100
p_i / (p_0 + p_1 + p_2 + ... + p_{i - 1} + x) <= k / 100
pi/(p0+p1+p2+...+pi−1+x)<=k/100
100
∗
p
i
<
=
k
∗
(
p
0
+
p
1
+
p
2
+
.
.
.
+
p
i
−
1
+
x
)
100 * p_i <= k * (p_0 + p_1 + p_2 + ... + p_{i - 1} + x)
100∗pi<=k∗(p0+p1+p2+...+pi−1+x)
100
∗
p
i
−
k
∗
(
p
0
+
p
1
+
p
2
+
.
.
.
+
p
i
−
1
)
<
=
k
∗
x
100 * p_i - k * (p_0 + p_1 + p_2 + ... + p_{i - 1} ) <= k * x
100∗pi−k∗(p0+p1+p2+...+pi−1)<=k∗x
最後得出
x
>
=
c
e
i
l
(
[
100
∗
p
i
−
k
∗
(
p
0
+
p
1
+
p
2
+
.
.
.
+
p
i
−
1
)
]
/
k
)
x >= ceil([100 * p_i - k * (p_0 + p_1 + p_2 + ... + p_{i - 1} ) ] / k)
x>=ceil([100∗pi−k∗(p0+p1+p2+...+pi−1)]/k)
從頭開始遍歷,找到最大的滿足條件即可
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int T, n, k;
typedef long long ll;
const int N = 110;
ll p[N];
void solve() {
cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> p[i];
ll res = 0, sum = p[1];
for(int i = 2; i <= n; i++) {
res = max(res, (100ll * p[i] - sum * k + k - 1) / k);
sum += p[i];
}
cout << res << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while(T--) solve();
return 0;
}
C
找到最大的環。
類似於數組裡最大的子序列問題
但是在dp轉移的時候需要進行一下特判,如果當前已經形成環了,那麼不在進行轉移。
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010;
int n, T;
int a[N], b[N];
long long dp[N];
void solve() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> dp[i];
dp[i]--;
//初始dp[i]的長度為c[i]的長度
}
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= n; i++) cin >> b[i];
long long res = 0;
for(int i = n; i > 1; i--) {
int d = abs(a[i] - b[i]);
res = max(dp[i] + d + 2, res);
if(d) dp[i - 1] = max(dp[i] + 2 + dp[i - 1] - d, dp[i - 1]); //如果當前兩點相交,那麼就已經構成環了,不能再想前轉移
}
cout << res << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while(T--) solve();
return 0;
}
D
D. Journey
由於走完一條路後,所有的路的方向會變反,那麼假如說當前的座標是x
如果x可以向左走,那麼向左走的最長長度為LRLR…交替的字串的長度
如果x可以向右走,那麼向右走的最長長度為RLRL…交替的字串的長度
這兩個可以預處理出來
程式碼如下:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 300010;
int n, T;
char str[N];
int r[N], l[N];
void solve() {
cin >> n;
cin >> str + 1;
int size = strlen(str + 1);
for(int i = 1; i <= size; ) {
int j = i; //j 是終點
while(j + 1 <= size && str[j + 1] != str[j])
j++;
for(int k = i - 1; k < j; k++)
if(str[k + 1] == 'R') r[k] = j - k + 1;
else r[k] = 1;
i = j + 1;
}
for(int i = size; i >= 1; ) {
int j = i; //j - 1是終點
while(j - 1 >= 1 && str[j - 1] != str[j])
j--;
for(int k = i; k >= j; k--)
if(str[k] == 'L') l[k] = k - j + 2;
else l[k] = 1;
i = j - 1;
}
for(int i = 0; i <= n; i++) {
if(!i) cout << r[i] << ' ';
else if(i == n) cout << l[i] << ' ';
else cout << r[i] + l[i] - 1 << ' ';
}
cout << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> T;
while(T--) solve();
return 0;
}