8.4集训

上午

考试

第一题

给你一个初始序列,和两个操作:操作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\)

晚上

没时间写了啊,**白某飞主任

你可能感兴趣的:(8.4集训)