Educational Codeforces Round 116 (Rated for Div. 2)
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;
}