Educational Codeforces Round 176 (Rated for Div. 2)补题

Codeforces Edu 176

A题链接

题面描述
给你两个整数 n 和 k ; k 是一个不小于 3 的奇数。您的任务是将 n 转化为 0 。
为此,您可以多次执行以下操作:从 1 到 k 中选择一个数字 x 并从 n 中减去它。但是,如果 n 的当前值是偶数(能被 2 整除),那么 x 也一定是偶数;如果 n 的当前值是奇数(不能被 2 整除),那么 x 一定是奇数
在不同的运算中,可以选择相同的 x 值,但并非必须如此。因此,使用 x 的相同值没有任何限制。
计算将 n 转化为 0 所需的最少运算次数。

思路:

  1. 贪心的考虑,如果当前 n 是偶数,直接选中 k-1操作 ceil(n/k) 次
  2. 如果当前x是奇数那么一次操作,就一定会改变奇偶性,那么操作一次后n变为偶数,只能选择偶数x-1进行操作,此时执行操作1即可

解题代码:

void solve(){
    ll n,k;cin>>n>>k;
    ll ans=0;
    if((n&1)&&n>=k) n-=k,ans++;
    ans+=(n+k-2)/(k-1);
    cout<<ans<<endl;
}

B题链接

题面描述
给你一个大小为 n 的整数数组 a 。最初,数组中的所有元素都被染成红色。
你必须从数组中选择恰好 k 个元素并将它们涂成蓝色。然后,在至少有一个红色元素的情况下,你必须选择任何一个有蓝色邻居的红色元素,并将其涂成蓝色。
绘制数组的代价定义为最初选择的 k 个元素与最后绘制的元素之和。
你的任务是计算给定数组的最大涂色成本。

思路:

  1. 首先考虑特殊情况(k=1)时,能选的最后一个数肯定是第一个或最后一个数
  2. 当(k != 1)时,考虑最后代价肯定是k+1个数之和,必定包含前k大的数(因为可以一开始就选前k大的数),那么考虑是否可以再选k+1大的数
  3. 注意到,最后一个选择的数肯定在前k个数中间或第一个与最后一个位置,当第k+1大的数不在这些区间时,考虑swap之前选择k个数中的一个,即第k+1大的数在前k次选择中选定,那么肯定可以保证选择的k+1个数是前k+1大的数

解题代码

void solve(){
    ll n,k;cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>a[i].first,a[i].second=i;
    ll ans=0;
    if(k==1){
        if(a[1].first>a[n].first) vis[1]=1;
        else vis[n]=1;
        ans=max(a[1].first,a[n].first),k--;
    }
    sort(a+1,a+1+n,greater<pair<ll,ll>>());
    for(int i=1;i<=k+1;i++){
        if(vis[a[i].second]) {
            k++;
            continue;
        }
        ans+=a[i].first;
    }
    cout<<ans<<endl;
    fill(vis,vis+1+n,0);
}

C题链接

题面描述
Monocarp 在他的避暑别墅里安装了一个新栅栏。栅栏由大小相同的 $$\(n\)$$ 块木板排成一排。
Monocarp 决定按照以下规则粉刷围栏:

  • 栅栏的每块木板都要涂上一种颜色;
  • 栅栏上的每块木板都要涂上恰好一种颜色; 每块木板要涂上的不同颜色的数量是恰好两种
  • 涂上相同颜色的栅栏木板必须形成一个连续的序列,也就是说,所有涂上相同颜色的木板对之间都没有涂上不同颜色的木板。
    Monocarp 公司有 m 种不同的油漆,其中 i 种颜色的油漆足以涂刷不超过 a _ i 块木板。Monocarp 不会再购买任何油漆。
    你的任务是确定满足 Monocarp 所描述的所有愿望的不同栅栏油漆方法的数量。如果有一块木板在这两种涂漆方式下被涂上了不同的颜色,那么这两种涂漆方式就被认为是不同的。

思路:

1.利用差分高效维护每种颜色的数量
2.顺序遍历计算每种颜色使用对应 \(n - a_i\) 再利用后缀数组计算每一个合法的后缀位置
3.减去每个位置重复计算的贡献值

解题代码

void solve(){
    int n,k;cin>>n>>k;
    vector<ll>a(k);
    vector<ll>g(n+1);
    vector<ll>suf(n+1);
    for(ll &x:a) cin>>x,g[x]++;
    for(int i=n-1;i>=1;i--){
        if(i==n-1) suf[i]+=g[i+1];
        suf[i]+=g[i];
        if(i+1<=n) suf[i]+=suf[i+1];
    }
    vector<ll>d(n+1);
    for(int i=n-1;i>=1;i--){
        d[i]+=suf[i];
        if(i+1<=n) d[i]+=d[i+1];
    }
    ll res=0;
    for(ll &x:a){
        res+=d[max(n-x,1LL)];
    }
    for(ll &x:a){
        if(x+x>=n) res-=min(n-1LL,x)-max(1LL,n-x)+1;
    }
    cout<<res<<endl;
}
posted @ 2025-03-18 23:53  usedchang  阅读(58)  评论(0)    收藏  举报