Educational Codeforces Round 116 (Rated for Div. 2)
阿新 • • 發佈:2021-12-22
Educational Codeforces Round 116 (Rated for Div. 2)
A.AB Balance
題目大意
有一個只包含a
和b
的字元穿s
, 問經過幾次變換可以使得字串中ab
和ba
的數量相同
每次變換為: 將一個字元變為另一種字元
思路
對於ab
和ba
的數量來說, 差值一定小於等於1
--原理我也不是很懂--, 舉個栗子好了, 字串的字串一定是abbba
或者abbb
的形式, 一個是相等, 另一個差一個, 不存在一種情況可以相差兩個以上
程式碼
#include <iostream> #include <string> using namespace std; int main() { int T; cin >> T; while (T --) { string str; cin >> str; int a = 0, b = 0; for (int i = 1; i < str.length(); i ++) if (str[i - 1] == 'a' && str[i] == 'b') a ++; else if (str[i - 1] == 'b' && str[i] == 'a') b ++; if (a > b) { for (char & i : str) if (i == 'a') { i = 'b'; break; } } else if (a < b) { for (char & i : str) if (i == 'b') { i = 'a'; break; } } cout << str << endl; } return 0; }
B.Update Files
題目大意
有n臺電腦, k條資料線, 每次每根線可以連結兩臺電腦完成資料傳輸, 問需要多少次
開始只有一臺電腦有
思路
首先是沒有全部用到k條時, 電腦數會成指數級倍增
然後超過之後, 會每次用k條
程式碼
#include <iostream> using namespace std; typedef long long LL; LL check(LL u, LL n) { LL ans = 0; LL cnt = 1; while (cnt < u && 1ll << ans < n) { ans ++; cnt *= 2; } return ans; } int main() { int T; cin >> T; while (T --) { LL n, k; cin >> n >> k; LL ans = 0, cnt = 1; while (cnt < k) { cnt *= 2; ans ++; } n -= cnt; if (n > 0) ans += (n + k - 1) / k; cout << ans << endl; } return 0; }
C - Banknotes
題目大意
有n種金錢和k個選擇, 每次可以選擇n種金錢中的一種, 問不能取到的最小組合時多少
思路
可以先想一個栗子,假如有面值為1和1000的鈔票,如果 k 大於1000的話,首選999張面值為1的鈔票,其餘的全部選1000面值的,很顯然這是最優解。如果換成100和100000呢?方式相同。由此就可以得知一個通法:從小到大對於每一對相鄰元素,在總數小於 k+1 的情況下加入 qmi(10, a[i] - a[i - 1] + 1) 張面值為 a[i-1] 的鈔票,如果大於等於 k+1,剩餘的鈔票全選面值為 a[i-1] 的。
程式碼
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll t,n,k,a[15],ans; ll cf(ll x){ ll xx=1; for(int i=1;i<=x;i++) xx*=10; return xx; } int main(){ scanf("%lld",&t); while(t--){ scanf("%lld%lld",&n,&k); memset(a,0,sizeof(a)); ans=0;k++; for(int i=1;i<=n;i++){scanf("%lld",&a[i]);} for(int i=2;i<=n;i++){ ll tot=cf(a[i]-a[i-1])-1; if(tot<k){ ans+=cf(a[i-1])*tot; k-=tot; } else{ ans+=cf(a[i-1])*k; k=0; } } if(k>0){ ans+=k*cf(a[n]); } printf("%lld\n",ans); } return 0; }
E - Arena
題目大意
有n個人, 每個人的血量不大於k, 每回合會對除自己之外的人攻擊, 問若干回合後同歸於盡的血量方案有多少
思路
f[i][j] 表示 有i個人, 血量都不大於j的方案有多少
- i- 1 >= j, 那麼不管怎麼樣, 第一回合之後所有人都會死亡, f[i][j] = qmi(j, i)
- i - 1 < j, 假設第一回合後剩餘k個人, 那麼這k個人又會進行血量不超過j - i + 1的新回合 f[i][j] += f[k][j - i + 1] * c(i, k) * (i - 1) ^ j
- 對於上一點, 仍有第一回合之後全部死亡的情況 f[i][j] += qmi(i - 1, i);
程式碼
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 510, mod = 998244353;
int n, x;
LL f[N][N];
LL c[N][N];
LL qmi(LL a, LL b) {
LL ans = 1;
while (b) {
if (b & 1) ans = (ans * a) % mod;
b >>= 1;
a = (a * a) % mod;
}
return ans;
}
int main() {
for (int i = 0; i < N; i ++) {
c[i][0] = c[i][i] = 1;
}
for (int i = 2; i < N; i ++) {
for (int j = 1; j <= i / 2; j ++) {
c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
c[i][i - j] = c[i][j];
}
}
cin >> n >> x;
for (int i = 2; i <= n; i ++) {
for (int j = 1; j <= x ; j ++) {
if (i - 1 >= j) f[i][j] = qmi(j, i) % mod;
else {
for (int k = 2; k <= i; k ++)
f[i][j] = (f[i][j] + f[k][j - i + 1] * c[i][k] % mod * qmi(i - 1, i - k)) % mod;
f[i][j] = (f[i][j] + qmi(i - 1, i)) % mod;
}
}
}
cout << f[n][x] << endl;
return 0;
}