1. 程式人生 > 其它 >Educational Codeforces Round 116 (Rated for Div. 2)

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;
}