zoukankan      html  css  js  c++  java
  • 7.22集训


    上午

    (cjh)学长讲课了,主要讲的动规

    1.线性dp

    典型例题

    摆花

    不会这个题(....!!!!!!)

    王八棋

    四个(if)四个(for) 注意计数器从(0)还是(1)开始的

    2.背包(他没讲)

    3.区间dp

    典型例题

    能量项链

    石子合并

    两个题几乎都一样

    给出区间dp的板子:

    初始化balbalbala.....
    for (int len = 2; len <= n; ++ len)
       for (int i = 1; i <= n-len+1; ++ i) {
          int j = i+len-1;
    	 for (int k = i; k < j; ++ k)
    	    f[i][j] = max/min(f[i][j],f[i][k]+f[k+1][j]*sth..)
    	}
    

    其中

    (f[i][j] = max/min(f[i][j], f[i][k]+f[k+1][j]*sth..))

    4.状压dp

    典型例题

    奶牛进电梯

    学长说题解第一种做法不太好

    最好是枚举子集 那样比较好
    PS

    枚举子集

    int S = 233333;
    for (int i = S; i; i = (i-1)&S)
       cout <<bitset<10>(i)<<'
    ';
    

    还有比较操蛋的插头dp

    甩个比较好的链接

    插头DP

    讲了到题 铺地板

    对于此题 我们枚举三个状态,但是这个题有点难,对于我这种初学者不太合适

    我们考虑一种简单的题:

    还是铺地板,不过没有障碍物,我们铺的都是直线,并且,直线都是长至少为2,宽固定为1

    对于这个题 我们规定 能继续延伸无论是横着或者竖着都是1

    如果不能继续延伸 规定为0

    然后每一行都是(2^{n}),有(n)行,所以复杂度为(n*2^{n})

    5.期望dp(他没讲)

    6.树形dp(他说是重点)

    有上司的舞会

    战略游戏

    前两个题目都差不多,主要是我们开个(f)数组,(0)表示这个点没来(或者是不选),(1)表示来(或者是选):(f[i][0/1])

    然后我们就可以根据他们的儿子来转移

    对于上面那道题

    (f[i][0] = sum{max(f[son][0], f[son][1])})

    (f[i][1] = sum{f[son][0]}+v[i])

    其中(v[i])表示(i)这个节点的快乐指数

    对于下面那道题

    (f[i][0] += f[son][1])

    (f[i][1] += min(f[son][0], f[son][1]))

    树上染色

    如图,我们假设节点(1)的下面有(k)个黑点,(x-->1)这条边为(val)

    我们考虑(val)对整个图形的影响

    设一共有(B)个黑点,(W)个白点

    (val)对整个图形的影响为:

    ((k*(B-k)+(s[1]-k)*(w-(s[1]-k))*val)

    其中(s[1])表示以(1)为祖先的子树的大小((size))


    下午

    一开始讲了一会,后来就做题了

    讲了一个虚树

    还有两个动规优化

    玩玩具的
    玩股票的

    对于玩玩具的那个:

    • 1找出(dp)式子

    • 2魔改

    • 3运用线性规划的知识与凸包的知识

    • 4用斜率优化来做他

    对于玩股票的那个:

    我们设(f[i][j])在第(i)天有(j)支股票能获得的最大价值

    • 1 凭空买

    (f[i][j] = -ap_{i}*j) 其中((0leq j leq as_{i}))

    • 2 不买也不买

    (f[i][j] = max(f[i-1][j], f[i][j])

    • 3 在之前的基础上买

    (f[i][j] = max(f[i][j], f[i-(w+1)][k]-(j-k)*ap{i})

    其中((j-as_{i}leq k <j))

    • 4在之前的基础上卖

    (f[i][j] = max(f[i][j], f[i-(w+1)][k]+(k-j)*bp_{i})

    其中((j<k leq j+bs_{i}))

    然后经过一系列(nb)操作就可以用单调队列来优化了...

    但是我既不会写代码也不会写优化

    连这些状态都是从题解看过来的

    晚上

    关于插头(dp)上午说的那个简单例题,学长给出了代码实现

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long int64;
    const int64 p = 1e9 + 7;
    
    void work(int n, int m)
    {
       unordered_map<int, int64> dp[2];
       int numnow = 0, numnext = 1;
       dp[numnow][0] = 1;
       for(int line = 1; line <= n; ++line)
       {
          for(int i = 1; i <= m; ++i)
          {
             dp[numnext].clear();
             for(auto s = dp[numnow].begin(); s != dp[numnow].end(); ++s)
             {
                int nowst = s->first, nowval = s->second;
                int u = (nowst >> i) & 1, l = (nowst >> (i - 1)) & 1;
                if(u == 0 && l == 0)
                {
                   (dp[numnext][nowst ^ (1 << i)] += nowval) %= p;
                   (dp[numnext][nowst ^ (1 << (i - 1))] += nowval) %= p;
                }
                if(u == 1 && l == 0)
                {
                   (dp[numnext][nowst ^ (1 << i)] += nowval) %= p;
                   (dp[numnext][nowst ^ (1 << i) ^ (1 << (i - 1))] += nowval) %= p;
                }
                if(u == 0 && l == 1)
                {
                   (dp[numnext][nowst ^ (1 << (i - 1))] += nowval) %= p;
                   (dp[numnext][nowst ^ (1 << i) ^ (1 << (i - 1))] += nowval) %= p;
                }
             }
             swap(numnow, numnext);
          }
          dp[numnext].clear();
          for(auto s = dp[numnow].begin(); s != dp[numnow].end(); ++s)
          {
             if(((s->first >> m) & 1) == 0)
                dp[numnext][s->first << 1] = s->second;
          }
          swap(numnow, numnext);
       }
       cout << dp[numnext][0] << endl;
    }
    
    int main()
    {
       int n, m;
       scanf("%d%d", &n, &m);
       work(n, m);
       return 0;
    }
    
    

    对于这份代码

    其中(u)(up)(l)(left) 分别代表上边和左边来的数字

    (nowst,nowval)分别代表当前这一行的状态,当前及以前已经拥有的方案数

    (从左往右更新的,因此(i)在右边,(i-1)在左边)

    对于特娘的三种(if)我们来画几个图

    对于这个图 我们u和l都为0也就是说,当前状态我们只能再向下或者右转移

    上图是(nowst)^(1<<(i-1))的情况 即向下开始直线

    向右延伸的直线,即(nowst)^(1<<i)

    至此(u = 0, l = 0)的情况结束。来看(u = 1, l = 0)的情况!

    (nowst)异或两次,即把第(i)位与第((i-1))位都取反了

    对于取反两次的情况,就是顺着原来的方向走,原来是竖着,现在还是竖着

    而上图右边的那个情况是 (nowst)^((1<<i)),即停止下渗

    至此(u = 1, l = 0)的情况结束。来看(u = 0, l = 1)的情况!

    (nowst)异或两次,即把第(i)位与第((i-1))位都取反了

    对于取反两次的情况,就是顺着原来的方向走,原来是横着着,现在还是横着

    而上图右边的那个情况是 (nowst)^((1<<(i-1)),即停止继续向左


    (End...)

  • 相关阅读:
    ESP8266简单几步建立服务器
    SVM推导
    标准的最大margin问题
    switch用法
    vecor预分配内存溢出2
    vector预分配空间溢出
    [面试编程题]算法基础-字符移位
    [面试编程题1]构造回文
    一天学完UFLDL
    神经网络中的XOR问题
  • 原文地址:https://www.cnblogs.com/yszhyhm/p/13367540.html
Copyright © 2011-2022 走看看