给出一个由 $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;
}