专栏文章
题解:P14258 好感(favor)
P14258题解参与者 23已保存评论 22
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 22 条
- 当前快照
- 1 份
- 快照标识符
- @minrsioj
- 此快照首次捕获于
- 2025/12/02 07:18 3 个月前
- 此快照最后确认于
- 2025/12/02 07:18 3 个月前
tag:贪心。
暴力
浮板只有 种状态,记忆化搜索即可。期望得分 。
贪心策略
首先确定最终要变成正面或者反面,不妨设为正面,实现时求出两种情况答案再取 即可。接下来我们将浮板分为需要翻面的(即反面)和不需要翻面的(即正面)。
将浮板 翻面时,总移动距离会增加 ,同时所有 的反面浮板 会移动到 ,这会使得它之后每次被翻面时需要的移动距离减少 。
如果有正面朝上的浮板被翻过面,不妨设其中被翻面时下标最小的一个当时为浮板 。则 前面没有浮板正面朝上时被翻面,因此每个浮板至多在反面朝上时被翻过一次面。从而若这一步不给 翻面,减少的移动距离为 ,前面的至多 个浮板每个翻面时的移动距离至多增加 ,因此总移动距离减少。
重复以上调整,可以得知只将反面浮板翻面,对于不需要翻面的浮板则从不翻面,能够达到最优答案。此时每个浮板至多翻面一次,同上分析得每次翻面对最终总移动距离的增加至少为 。
如果某一次将 翻面时浮板 为反面,则它会被移动到 ,而在将 翻面前先将 翻面只需要移动 。因此每当一个反面浮板到达 ,则优先将它翻面。
显然此时我们可以贪心地每次选取最大的 ,这样最初的每个反面浮板 最终实际需要的移动距离为 。容易证明这是最优答案。
直接模拟上述翻面过程可以做到 ,期望得分 。
Code:
CPPint m;
int p[1000003];
inline ll calc(){
ll res=0;
for(int i=m;i>0&&p[i]>=1;--i){
res+=p[i];
for(int j=i-1;j>0&&p[j]>=1;--j){
if(p[j]==1)++res;
--p[j];
}
}return res;
}
int n;
ll rs0,rs1;
char s[1000003];
inline void solve(){
cin>>n>>s+1;m=0;
for(int i=1;i<=n;++i)
if(s[i]=='0')p[++m]=i;
rs0=calc();m=0;
for(int i=1;i<=n;++i)
if(s[i]=='1')p[++m]=i;
rs1=calc();cout<<min(rs0,rs1)<<"\n";
}
特殊性质
其实是为了多给点部分分。可以直接计算将前 个正面变为反面需要的移动距离为 ,将后 个反面变为正面需要的移动距离为 。注意后一个式子没有考虑 过大的情况,但事实上这时前一部分的答案总是较小,因此直接对以上两结果取 即可。期望得分 ,结合朴素贪心期望得分 。
正解
事实上由上面得出的移动距离公式可以 计算出每个浮板 的贡献。
具体实现中可以记录一个变量 表示现在已经翻了几个浮板。枚举要翻面的浮板最大下标 ,同时记录剩余的最小下标 ,将最大浮板翻面移动距离为 ,若它是第 个被翻面的浮板并且 ,则这次翻面时 到达了 的位置,如果 不等于刚刚翻面的 则直接给答案加上 ,并处理掉 。
总时间复杂度 ,期望得分 。记得开
long long。Code:
CPPint m;
int p[1000003];
inline ll calc(){
ll res=0;
for(int i=1,j=m,c=0;j>=i;){
res+=p[j]-c;++c;--j;
if(i<=j&&p[i]==c)++res,++i;
}return res;
}
相关推荐
评论
共 22 条评论,欢迎与作者交流。
正在加载评论...