您的位置:首页 > 其它

【年前的胡策】训练2.12(贪心)

2018-02-12 21:12 363 查看




题解:

首先显而易见的:填棋子的过程就是划分区间的过程,那么为了框出边界,我们需要在1,n上填好

然后就在考场上傻傻的讨论区间的奇偶性,过了样例就跪了大数据,果然不证明的结论都是胡扯。

实际上这道题目有一个结论

f[x]=__builtin_popcount(x)-1

__builtin_popcount(x):x的二进制中有多少个一

怎么跟二进制扯上关系的?



我们可以发现:如果一开始0号位有棋子,为了让1号位的棋子免费,我们需要填上2号位的格子

为了让2号位的棋子免费,我们需要填上4号位的棋子…….

2的幂啊,我们发现这样填的话首先填16的话这一堆都不用管了

因此,我们在相邻的两个棋子之间,只有把棋子放在2的整数幂的位置才能保证答案最小

我们利用倍增的思想,贪心的往空隙中放置相聚尽量远且位置是2的整数幂的棋子(因为这样中间的都不用管了)

代码:

#include <cstdio>
#include <algorithm>
#define LL long long
4000
using namespace std;
int m;LL a[10],n;
int work(LL x)
{
int ans=0;
while (x) ans+=(x&1),x>>=1;
return ans;
}
int main()
{
freopen("chess.in","r",stdin);
freopen("chess.out","w",stdout);
scanf("%lld%d",&n,&m);
if(m==0)
{
printf("%d",work(n-1)+1);
return 0;
}
bool h1=0,hn=0;
for(int i=1;i<=m;i++)
{
scanf("%lld",&a[i]);
if (a[i]==1) h1=1;
if (a[i]==n) hn=1;
}
int ans=0;
if (!h1) a[++m]=1,ans++;
if (!hn) a[++m]=n,ans++;
sort(a+1,a+m+1);
for(int i=2;i<=m;i++) ans+=work(a[i]-a[i-1])-1;
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: