今天又垫底了。。。
T1:这题的方法十分巧妙,我当场没有想出来。
其实我们的目的就是要把n-1个数变成0,而剩下的那一个数变成2^k。换句话说,就是把n个数的二进制表示形式变成n-1个0,1个10...0,。那也就是要我们尽可能的多消掉1。
所以我们可以这样做:
先把n个数都化成二进制形式,然后我们先考虑把最后一位的1给消掉。因为这n个数的和为2^k,所以一定有偶数个数的二进制形式的末尾为1,所以我们可以把这些数两两组合,这样就可以把最后一位的1消掉,接下来的第二,第三位等同理。最终就可以求出一种方案。
总结:这题的本质就是找所有操作相同的地方,首先发现*2就是在二进制表示形式的末尾加上一个0,进而发现有偶数个末尾为1的数,从而解决问题。其实好像石子问题都是这样的。
T2:首先设f[i]表示第i个位置的答案,那么f[i]=min(f[j]+(i-j)*a[j]+b[i])(1<=j<i),这样只能拿50分,所以我们可以考虑队列优化。
首先,若有j<j'且a[j]>a[j']且f[j]+(i-j)*a[j]>f[j']+(i-j')*a[j'],那么j一定是不如j'优的。
所以,我们可以把有用的位置存下来,以后只需搜索这些位置就可以了,关键是怎么存?
假设当前已经算出f[i],我们要把i放入序列,并且要把不如i优的踢出序列,那么若序列中有一个j满足a[j]>a[i]或f[i]+(i-i)*a[i]>f[j]+(i-j)*a[j]也就是f[i]>f[j]+(i-j)*a[j],那么这个j是要被留下的。具体实现可以用两个数组互相滚动,这样可以快很多。
总结:比赛时爆0,这里总结一下对这类dp的优化。
若要用单调栈优化,那么一定要针对转移方程中所有不确定元素来建栈,不能只针对某一部分。比如这道题,应该针对f[j]+(i-j)*a[j]来建栈,而比赛时我只针对了a[i]来建栈。
T3:这题十分水,而比赛时我却因为文件输入输出打错而爆0。
正解就是把行纵坐标排个序,然后直接模拟就行了。注意:要用二分来查找。