Educational Codeforces Round 176 (Rated for Div. 2)补题
Codeforces Edu 176
题面描述
给你两个整数 n 和 k ; k 是一个不小于 3 的奇数。您的任务是将 n 转化为 0 。
为此,您可以多次执行以下操作:从 1 到 k 中选择一个数字 x 并从 n 中减去它。但是,如果 n 的当前值是偶数(能被 2 整除),那么 x 也一定是偶数;如果 n 的当前值是奇数(不能被 2 整除),那么 x 一定是奇数。
在不同的运算中,可以选择相同的 x 值,但并非必须如此。因此,使用 x 的相同值没有任何限制。
计算将 n 转化为 0 所需的最少运算次数。
思路:
- 贪心的考虑,如果当前 n 是偶数,直接选中 k-1操作 ceil(n/k) 次
- 如果当前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;
}
题面描述
给你一个大小为 n 的整数数组 a 。最初,数组中的所有元素都被染成红色。
你必须从数组中选择恰好 k 个元素并将它们涂成蓝色。然后,在至少有一个红色元素的情况下,你必须选择任何一个有蓝色邻居的红色元素,并将其涂成蓝色。
绘制数组的代价定义为最初选择的 k 个元素与最后绘制的元素之和。
你的任务是计算给定数组的最大涂色成本。
思路:
- 首先考虑特殊情况(k=1)时,能选的最后一个数肯定是第一个或最后一个数
- 当(k != 1)时,考虑最后代价肯定是k+1个数之和,必定包含前k大的数(因为可以一开始就选前k大的数),那么考虑是否可以再选k+1大的数
- 注意到,最后一个选择的数肯定在前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);
}
题面描述
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;
}

浙公网安备 33010602011771号