CF1415C Bouncing Ball 题解

题意分析

给出一个由 $0,1$ 组成的序列,要从第 $p$ 个位置开始,每次跳 $k$ 个单位,要求跳出序列,只有当所有经过的位置都为 $1$ 才合法。你可以花费 $x$ 将这个序列的第一个元素删除,也可以花费 $y$ 将其中一个位置改为 $1$ ,求能合法跳出序列的最小修改花费。

思路分析

发现当第一个位置确定后,后面的所有跳到的位置都可以确定,考虑枚举删去的元素数量,即起始位置。

显然前 $p-1$ 个元素都是无用的,可以不管它们,然后设为从第 $1$ 个位置开始。

假设删去前 $i$ 个元素,那么很容易可以得出需要跳的次数:$left lceil frac{(n-i)}{k} ight ceil$ 。然后需要知道被跳到的地方有多少个位置为 $0$ ,这个可以把整个序列按照对 $k$ 的模数进行分类,然后对于每一类预处理出为 $1$ 的个数,处理的时候再统计当前位置之前的 $1$ 的个数,就可以得出后面的 $0$ 的个数。最后加上删去 $i$ 个元素的花费即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath> 
using namespace std;
const int N=1e5+100;
int T,n,p,k,x,y,ans;
int cnt[N],ncnt[N];
string s;
void clear()
{
    memset(cnt,0,sizeof(cnt));//整个序列中 1 的个数
    memset(ncnt,0,sizeof(ncnt));//当前位置之前的 1 的个数
    ans=1e9;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        clear();
        scanf("%d%d%d",&n,&p,&k);cin>>s;scanf("%d%d",&x,&y);
        for(int i=p-1;i<n;i++)
            cnt[(i-p+1)%k]+=s[i]-'0';//预处理 1 的个数
        for(int i=p-1;i<n;i++)
            ans=min(ans,((int)ceil((double)(n-i)/k)-cnt[(i-p+1)%k]+ncnt[(i-p+1)%k])*x+(i-p+1)*y),ncnt[(i-p+1)%k]+=s[i]-'0';
        printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TEoS/p/14084101.html