Educational Codeforces Round 116 (Rated for Div. 2)

Educational Codeforces Round 116 (Rated for Div. 2)

A.AB Balance

题目大意

有一个只包含ab的字符穿s, 问经过几次变换可以使得字符串中abba的数量相同
每次变换为: 将一个字符变为另一种字符

思路

对于abba的数量来说, 差值一定小于等于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;
}
posted @ 2021-12-22 20:18  哇唔?  阅读(35)  评论(0编辑  收藏  举报