题目描述
forever97准备举办一场夏日祭,他邀请了许多参展商,并为每位参展商各准备了一串灯笼。
灯笼串可以表示为一个长度为n的字符串,其中每个字符表示一个小灯笼,共有10种小灯笼,分别用0到9表示。
每家参展商都对灯笼串有一定要求,所有符合第 k 家参展商要求的灯笼串所构成的集合,被称为 S[k] 。S[k] 内的任意元素 s ,必须满足以下要求:
1.若 s 的长度 n=1,则 s 仅包含一个数字 d ,d=k%10;
2.若 s 的长度 n>1 且 n 为偶数,则 s(1,n/2)∈S[k+1],s(n/2+1,n)∈S[k];
3.若 s 的长度 n>1 且 n 为奇数,则 s(1,(n-1)/2)∈S[2k],s((n+1)/2, (n+1)/2)∈S[k],s((n+1)/2+1, n)∈S[2k];
*其中 s(l,r) 表示从字符串 s 的第 l 个字符到第 r 个字符所构成的子串,编号从1开始计数。
*其中 x∈S[y] 表示元素 x 属于集合 S[y],即 x 满足第 i 家参展商的美观要求。
给定一串由字符串表示的灯笼串 a,请问需要替换其中几个灯笼,才能符合第k家参展商的要求?
分析
这道题看起来比较难做,但从要求来看,可以发现对于第
k
k
k家的参展商,其所对应的字符串是唯一的
于是这这就变成一个递归构造的题目,而且题目中的三个要求便是递归中的条件和边界
而递归中的参数,也很好表示,第一个便是
n
n
n,此处的
n
n
n相较于题目中的,含义则变成了当前构造的字符串的长度,
k
k
k是当
n
=
1
n=1
n=1时当前位上的字符,然后再加一个
l
l
l,代表当前构造的起始位置
于是,
1.若 s 的长度 n=1,则 s 仅包含一个数字 d ,d=k%10;
的代码实现为
if (n==1)
{
ans[l]=k%10+'0';
return;
}
2.若 s 的长度 n>1 且 n 为偶数,则 s(1,n/2)∈S[k+1],s(n/2+1,n)∈S[k];
3.若 s 的长度 n>1 且 n 为奇数,则 s(1,(n-1)/2)∈S[2*k],s((n+1)/2, (n+1)/2)∈S[k],s((n+1)/2+1, n)∈S[2*k];
的代码实现为
if (n%2)//当n为奇数时
{
dfs((n-1)>>1,k<<1,l);
ans[l+(n-1)/2]=k%10+'0';//因为题目要求中的l为1,所以题目中的式子就合并为(n+1)/2了
dfs((n-1)>>1,k<<1,l+(n+1)/2);//长度为n-(n+1)/2-1+1,即(n-1)/2
}
else//当n为偶数时
{
dfs(n/2,k+1,l);
dfs(n/2,k,l+n/2);
}
要注意左移的运算顺序在加减的后面
(刚重构代码时调了好久才发现是这个错误)
然后再与输入的s字符数组逐位比较,输出不同的位数即可
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
char ans[200200],s[200200];
ll n,m,i,j,k,l,o,p;
void dfs(ll n,ll k,ll l)
{
if (n==1)
{
ans[l]=k%10+'0';
return;
}
if (n%2)
{
dfs((n-1)>>1,k<<1,l);
ans[l+(n-1)/2]=k%10+'0';
dfs((n-1)>>1,k<<1,l+(n+1)/2);
}
else
{
dfs(n/2,k+1,l);
dfs(n/2,k,l+n/2);
}
}
int main()
{
scanf("%lld%lld",&n,&k);
dfs(n,k,1);
scanf("%s",s);
for (i=1;i<=n;i++)
if (s[i-1]!=ans[i]) l++;
printf("\n%lld\n",l);
}```