这道题,真香。 (话说shashlik好像是毛子们/东欧地区人民热爱的,一种类似于烤串的美食,wiki上的图片看起来很香的样子) 嗯大概就是这个。 题目大意: Miroslav正在烤串。 众所周知
这道题,真香。
(话说shashlik好像是毛子们/东欧地区人民热爱的,一种类似于烤串的美食,wiki上的图片看起来很香的样子)
嗯大概就是这个。
题目大意:
Miroslav正在烤串。
众所周知烤串是要翻动的。
有n个烤串,每个串一开始都是正面朝上的。对于某个烤串进行翻动操作,会使这个串以及相邻左右k个串都被翻动。
翻动会使正面朝上的串翻到反面,反面朝上的串翻到正面。
求最少翻动几次能够将n个串全部翻到反面。
输出最少翻动次数,以及翻动哪些串。
程式化的描述:
给定一个初始为0的数组,每次对 $ i $ 操作会使 $ [i-k,i+k] $ 之间的所有数字取反(0->1,1->0),最少操作多少次能够将整个数组变为1。
输出最少操作次数,以及操作数组的哪些元素。
题解:
首先是求最小操作次数。不难发现,每个串 $ i $ 都控制着 $ [i-k,i+k] $ 的区域。也就是说,每个串控制长度为 $ k*2+1 $ 的区域。
我们从1开始,枚举使用多少个长度为 $ k*2+1 $ 的区域,能把 $ n $ 覆盖掉。
$ ans $ 为需要翻转的烤串数量(最少翻动次数)。
int ans=0; while(ans*(2*k+1)<n)ans++; printf("%d\n",ans);
然后是求这些烤串的位置。
先求最左边的烤串的位置 $ l $ ,从1到 $ k+1 $ 枚举,因为每个烤串之间距离是已知的 $ (2k) $ ,所以可以算出最右边的烤串位置为 $ l+(ans-1)((2*k)+1) $
如果最右边的位置+k大于等于n,就可以了。
int l=1; for(;l<=k+1 and (l+(ans-1)*((2*k)+1)+k)<n;l++){}
最后从 $ l $ 开始,下一个串的位置等于上一个的位置+ $ (2*k)+1 $ ,逐个输出就好了。
printf("%d ",l); while(l+k<n){ l=l+(2*k)+1; printf("%d ",l); }