上午
考试
第一题
给你一个初始序列,和两个操作:操作1可以使得\(i\)与\(i+2\)两个数交换位置,操作2是相邻的数可以交换位置
问:这个序列最少用多少次操作2可是使序列单调递增?
你考虑,操作1的性质:使得\(i\)与\(i+2\)两个数交换位置,不就是奇偶性相同的位置吗?而操作2的性质:相邻的数可以交换位置,不就是奇偶性不同的数吗?
把原序列排序之后,对于为排序的序列,我们考虑当前这个数的下标与排完序之后的下标,如果发现他们奇偶性相同,也就是说,可以经过若干次操作1可以变换到那个位置
如果发现奇偶性不同,说明肯定是经过了一次操作1,因此计数器叠加
注意细节:这样统计是真实答案的二倍,因为:假如当前在\(i\),你发现这个数排完序之后在\(j\)(\(i < j\)),且\(i,j\)的奇偶性不同,这时你计数器累加,但是到了\(j\)那个位置,你的计数器还会叠加,也就是说,你的计数器对于同一种情况增加了两次
#include
#define LL long long
#define debug
using namespace std;
const int N = 2e5+66;
int n, res;
int a[N], b[N];
inline int thestars() {
cin >> n;
for (int i = 1; i <= n; ++ i) {
cin >> a[i];
b[i] = a[i];
}
sort(b+1, b+n+1);
for (int i = 1; i <= n; ++ i) {
int pos = lower_bound(b+1, b+n+1, a[i]) - b;
if ((pos&1) != (i&1)) ++ res;
}
cout << (res/2);
return 0;
}
int youngore = thestars();
signed main() {;}
下午
讲dp!!!
我们来通过通过几道例题来体会一下什么是dp
01背包
将n件有着各自体积和价值的物品装入一个容积为m的背包中,求最大的总价值
状态:\(f[i][j]\)表示前\(i\)件物品放入背包为\(j\)的背包中所能获得的最大总价值
转移:\(f[i][j] = max(f[i-1][j], f[i-1][j-v[i]]+w[i])\)
结果:\(f[n][m]\)
最长不下降子序列
给出一个长度为n 的序列,求最长的子序列,满足这些元素依次不减
状态:设\(f[i]\)表示以\(i\)为结尾的最长不下降子序列的最长长度
转移:\(f[i] = max(f[j]+1)\)其中\(a[j]
结果:\(max(f[i])\)
上面是\(O(n^2)\)做法,还有一种\(O(nlogn)\)的做法:
状态:设\(f[i]\)表示长度为\(i\)的的最长不下降子序列的最后一个元素的最小值
举个例子:
有序列\(a[] = {8,2,3,5,7,6,4}\),所以可得:
\(f[0] = 0,f[1] = 2, f[2] = 3, f[3]=5,f[4]=7\)(第一遍扫)
遇到\(6\)考虑更新\(f[4]\),遇到\(4\)考虑更新\(f[3]\)
至于为什么是logn的,因为每次是二分查找(\(lower\)_\(bound\)是log的)
再次考虑\(dp\)的牛逼之处: 需要有易于表示的状态,能够列出的转移,便于计算的结果
要把式子推出来再去写代码
下面有几道一般dp,没什么特点,就是难
渡河问题
click
状态:\(f[i]\)表示将前\(i\)头牛运到对岸的时间
转移:\(f[i] = min(f[j]+2*M+sum[i-j])\)其中\(sum\)为前缀和
结果:\(f[n]\)
解题
click
给出贪心的\(Hack\)数据:
50 5
40 10
10 40
10 5
10 3
10 2
状态:\(f[i][j]\)表示处理\(1\)到\(j\)的题,最后一次选择了\(i\)到\(j\)的最短月数
转移:\(f[i][j] = min(f[k][i-1]+1/2)\)其中剩下的钱足够就是\(+1\)否则是\(+2\)
结果:\(min(f[i][p])+1\)
晚上
没时间写了啊,**白某飞主任