Educational Codeforces Round 86 (Rated for Div. 2)【ABCDE】(题解)

涵盖知识点:思维、前缀和、组合数学

比赛链接:传送门

A - Road To Zero

题意: 给定(x,y,a,b),花费(a)可以使(x,y)其中一个加一或者减一,花费(b)可以使(x,y)同时加一或者减一。问最少花费多少使得(x=y=0)
题解: 判断(2a)(b)的大小贪心。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--){
        int a,b,x,y;
        cin>>x>>y>>a>>b;
        if(x>y)swap(x,y);
        cout<<1ll*min(2*a,b)*x+1ll*a*(y-x)<<"
";
    }
    return 0;
}

B - Binary Period

题意: 给定01串(t),要求构造一个(s)满足(t)(s)的子序列且(|s|le 2|t|),并且拥有尽量小的周期。
题解:(t)全同:(s=t),否则(s=01010101ldots)
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int main(){
    int t;cin>>t;
    while(t--){
        string s;
        cin>>s;
        bool f[2]={false,false};
        for(char i:s)f[i-'0']=true;
        if(!f[0]||!f[1])cout<<s<<"
";
        else{
            for(int i=0;i<s.length();i++)cout<<"01";
            cout<<"
";
        }
    }
    return 0;
}

C - Yet Another Counting Problem

题意:(iin[l,r])中有多少数满足(i\% a\%b ot =i\%b\%a)
题解: 式子具有周期性。计算([0,ab))区间内满足数量的前缀和处理一下就行了。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+10;
int sum[maxn];
ll a,b,q;
ll calc(ll x){
    return 1ll*x/(a*b)*sum[a*b]+1ll*sum[x%(a*b)];
}
int main(){
    int t;cin>>t;
    while(t--){
        memset(sum,0,sizeof sum);
        cin>>a>>b>>q;
        for(int i=1;i<=a*b;i++)sum[i]+=sum[i-1]+(i%a%b!=i%b%a);
        while(q--){
            ll l,r;
            cin>>l>>r;
            cout<<calc(r)-calc(l-1)<<" ";
        }
        cout<<"
";
    }
    return 0;
}

D - Multiple Testcases

题意: 尽可能少的拆分给定序列,使得每个序列内大于等于(k)的数的个数不超过(c_k)
题解: 假设原有序列大于等于(k)的数为(s_k),则(ans=displaystylemax_{1le ile k}{lceilfrac{s_i}{c_i} ceil})。确定(ans)以后从小到大依次分配即可。
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+10;
int s[maxn],m[maxn],c[maxn];
vector<int> v[maxn];
int main(){
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++)cin>>m[i],s[m[i]]++;
    sort(m,m+n);
    for(int i=1;i<=k;i++)cin>>c[i];
    for(int i=k-1;i>=1;i--)s[i]+=s[i+1];
    int ans=0;
    for(int i=1;i<=k;i++)ans=max(ans,(s[i]-1)/c[i]+1);
    for(int i=0,j=0;j<n;i=(i+1)%ans,j++)v[i].push_back(m[j]);
    cout<<ans<<"
";
    for(int i=0;i<ans;i++){
        cout<<v[i].size();
        for(auto j:v[i])cout<<" "<<j;
        cout<<"
";
    }
    return 0;
}

E - Placing Rooks

题意: 在一个(n*n)的棋盘上放置(n)个车,满足以下两个条件:

  1. 棋盘上的每一个空格子都能被至少一只车走到
  2. 恰好存在(k)对车可以相互攻击

询问所有车的摆放方案数
题解: 要满足第一个条件,则每一行/每一列都有一个车,两者至少满足其一。对于这两种情况是等价的,下面只考虑每一行都有车,最终结果乘(2)即可
在满足第二个条件的情况下,可以发现至少有(k)列是空着的,那么问题就相当于把(n)个不同的车放入(n-k)个不同的列,发现就是一个第二类斯特林数。那么可以用容斥原理,(C_{n-k}^{0}*(n-k)^n-C_{n-k}^{1}*(n-k-1)^n+C_{n-k}^{2}*(n-k-2)^n...),那么最终答案就是(2*C_{n}^{n-k}*[C_{n-k}^{0}*(n-k)^n-C_{n-k}^{1}*(n-k-1)^n+C_{n-k}^{2}*(n-k-2)^n...])
要注意特判一下当(n=0)时,答案就为(n!),当(kge n)时,答案为(0)
第二类斯特林数详解传送门
Accept Code:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
const int mod = 998244353;
ll fac[maxn];
ll qpow(ll a, ll b){
    ll res = 1;
    while (b){
        if (b & 1)
            res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}
void init(){
    fac[0] = 1;
    for (int i = 1; i < maxn; i++)
        fac[i] = fac[i - 1] * i % mod;
}
ll c(int x, int y){
    return fac[x] * qpow(fac[y] * fac[x - y] % mod, mod - 2) % mod;
}
int main(){
    init();
    int n, k;
    cin>>n>>k;
    if (k == 0){
        cout<<fac[n]<<"
";
        return 0;
    }
    if (k >= n){
        cout<<"0
";
        return 0;
    }
    ll ans = 0;
    for (int i = 0; i <= n - k; i++)
        ans += 1ll * qpow(mod - 1, i) * c(n - k, i) % mod * qpow(n - k - i, n) % mod;
    ans %= mod;
    cout<<2ll * ans % mod * c(n, n - k) % mod<<"
";
    return 0;
}
原文地址:https://www.cnblogs.com/charles1999/p/12785134.html