2016 10 27 考试 dp 向量 乱搞

这篇博客主要回顾了2016年10月27日的一场考试,重点讨论了动态规划(dp)在解决问题中的应用,以及向量在数学和编程中的运用。通过实例分析,博主深入浅出地解释了如何利用dp解决复杂问题,并探讨了向量运算在算法设计中的重要作用。


[TOC]

20161027考试

考试时间 7:50 AM to 11:15 AM

题目
考试包


据说这是一套比较正常的考卷,,,嗯,,或许吧,
jk
而且,,整个小组其他人的分数加起来也不如apt123大神多,,
最终,3道题一共30分滚粗
mo

T1:

树形dp题目,感觉我这种dp渣渣是想不出方程了,,%%%%一下apt大神,,

正解:

设dp[i][j]表示根节点为i,距离i最近的被选点的距离大于等于j时的最大节点数,dp[i][0]即为答案

转移:

设f[i][0] = a[i],表示选了a[i]后的初始状态,转移方程为:

dp[i][j] = max(dp[i][j] + dp[son[i]][max(k - j, j - i)], dp[i][max(k - j + 1, j)] + dp[son[i]][j - 1]); j = 1 -> k

dp[i][j] = max(dp[i][j], dp[i][j+1]);

考虑方程,显然设置状态时并没有考虑到同一个根的不同儿子之间的冲突情况,所以必须在转移时候加以限制。

  • 当j的值足够大时,该根节点的j层儿子之间一定不会发生矛盾,因此可以由dp[son[i]][j-1]向dp[i][j]转移

  • 当j的值比较小时,同层的子节点会发生冲突,那么就必须手动解决冲突,即将其中一个点设为k-j,以保证两个子节点之间的距离大于k

再考虑dp方程本身的含义,显然可知对于dp[i][j],随着j变小可选择的范围应逐渐增多,即如果dp[i][3] = 4,dp[i][1]最少为4,由此,再转移后再加入dp[i][j] = max(dp[i][j], dp[i][j+1])

#include <cstdio>
#include <algorithm>
#include <cstring>
using std :: max;
const int maxn = 20000 + 100;
int last[maxn], pre[maxn], other[maxn];
int f[maxn][120];
int n, k;
int a[maxn];
int tot = 0;
int x1, x2;

void add(int x, int y) {
    tot++;
    pre[tot] = last[x];
    last[x] = tot;
    other[tot] = y;
}

void dfs(int x, int from) {
    f[x][0] = a[x];
    for (int p = last[x]; p; p = pre[p]) {
        int q = other[p];
        if (q == from) continue;
        dfs(q, x);
        f[x][0] = f[x][0] + f[q][k];
        for (int j = 1; j <= k; j++) {
            f[x][j] = max(f[x][j] + f[q][max(k - j, j - 1)], f[x][max(k - j + 1, j)] + f[q][j-1]);
        }
    }
    for (int i = k-1; i >= 0; i--) f[x][i] = max(f[x][i+1], f[x][i]);
}

int main () {
    freopen("score.in", "r", stdin);
    freopen("score.out", "w", stdout);
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
    for (int i = 1; i < n; i++) {
        scanf("%d %d", &x1, &x2);
        add(x1, x2);
        add(x2, x1);
    }
    dfs(1, 0);
    printf("%d", f[1][0]);
    return 0;
}

再贴上apt大犇的AC代码,代码略长但更为直观

var
    n,m,a,b,bg                 :longint;
    f                       :array[0..10010,0..105]of longint;
    pre,oth,last,q,w          :array[0..20010]of longint;
    vis                     :array[0..10010]of boolean;
    ii,i,j,k,p,r                   :longint;
    totl,ans,ret,mxs             :longint;

function max(a,b:longint):longint;
begin
    if a>b then exit(a); exit(b);
end;

procedure conn(a,b:longint);
begin
    inc(totl);
    pre[totl]:=last[a];
    last[a]:=totl;
    oth[totl]:=b;
end;

procedure bfs;
var p,cur,r,he,ta:longint;
begin
    he:=0; ta:=1; q[1]:=1; vis[1]:=true;
    while he<>ta do begin
        inc(he);
        cur:=q[he];
        p:=last[cur];
        while p>0 do begin
            r:=oth[p];
            if not vis[r] then begin
                vis[r]:=true;
                inc(ta);
                q[ta]:=r;
            end;
            p:=pre[p];
        end;
    end;
end;


begin
    assign(input,'score.in'); reset(input);
    assign(output,'score.out'); rewrite(output);

    read(n,m);
    for i:=1 to n do read(w[i]);
    for i:=1 to n-1 do begin
        read(a,b);
        conn(a,b); conn(b,a);
    end;
    bfs;

    bg:=(m>>1)+1;

    for ii:=n downto 1 do begin
        i:=q[ii];
        f[i,0]:=w[i];
        p:=last[i];
        while p>0 do begin
            r:=oth[p];
            inc(f[i,0],f[r,m]);
            p:=pre[p];
        end;

        for k:=m downto bg do begin
            f[i,k]:=f[i,k+1];
            ret:=0;
            p:=last[i];
            while p>0 do begin
                r:=oth[p];
                inc(ret,f[r,k-1]);
                p:=pre[p];
            end;
            f[i,k]:=max(f[i,k],ret);
            //if (k=3)and(i=1) then writeln('??',ret,' ',f[3,2],' ',f[i,k]);
        end;

        for k:=bg-1 downto 1 do begin
            f[i,k]:=f[i,k+1];
            ret:=0; mxs:=0;
            p:=last[i];
            while p>0 do begin
                r:=oth[p];
                inc(ret,f[r,m-k]);
                p:=pre[p];
            end;
            p:=last[i];
            while p>0 do begin
                r:=oth[p];
                f[i,k]:=max(f[i,k],ret-f[r,m-k]+f[r,k-1]);
                p:=pre[p];
            end;

            {if (k=2)and(i=1) then writeln('??',ret,' ',mxs,' ',f[2,1]);
            f[i,k]:=max(f[i,k],f[mxs,k-1]+ret-f[mxs,m-k]);  }
        end;
        f[i,0]:=max(f[i,0],f[i,1]);
    end;

    {for i:=1 to n do begin
        for j:=0 to m do begin
            write(f[i,j],' ');
        end;
        writeln;
    end;  }

    for i:=0 to m do
        ans:=max(ans,f[1,i]);

    write(ans);

    close(input);
    close(output);
end.

T2:

线性dp,状态定义和转移都比较邪,,,
考试时把题目理解成处理玉的方案数,导致前期思路错误,未能完成题目

正解:

F[i]表示到了第i天恰好第一次出现k个连续的晴天的方案数,那么要保证i-k这一天一定是雨天或者X,于是i-k+1~i这一段的天气已经全部被固定了,可以得出方案数有2^(1~i-k中X的个数),然后减去所有不合法的状态,对于Fj就减去F[j]2^(j+1~i-k中X的个数)(可以记一个数组t1,每次遇到X就2,每次都加上F[i]的值),(j>i-k)的就是减去F[j],对于雨天反过来做一次,最后答案是sigma(F[i]*雨天的t1[i+1])

实现:

使用numx, numw, numb记录每种天气出现的次数,为方便期间,numx, numb 从1开始,numw从n逆向开始

转移

当题设条件满足时,f[i] = 2 ^ (numx[i-k-1]) - t[i - k - 1], ts[i] = (ts[i-1]) * (1 + (当前为x) ) + f[i]。

代码:
#include <cstdio>
#include <cstring>
#include <algorithm>

const int mod = 1000000007;
const int maxn = 1000000 + 100;
int n, k;
char s[maxn];
long long pow2[maxn];
int numb[maxn], numw[maxn], numx[maxn];
long long fs[maxn], fr[maxn], ts[maxn], tr[maxn];
int main () {
    freopen("jade.in", "r", stdin);
    freopen("jade.out", "w", stdout);
    scanf("%d %d", &n, &k); 
    scanf("%s", s + 1);
    s[0] = 'X';
    s[n+1] = 'X';
    pow2[0] = 1;
    for (int i = 1; i <= n; i++) pow2[i] = (pow2[i-1] * 2) % mod;
    for (int i = 1; i <= n; i++) numb[i] = numb[i-1] + (s[i] == 'B');
    for (int i = n; i >= 1; i--) numw[i] = numw[i+1] + (s[i] == 'W');
    for (int i = 1; i <= n; i++) numx[i] = numx[i-1] + (s[i] == 'X');
    for (int i = k; i <= n; i++) {
        if ((numb[i] - numb[i-k] + numx[i] - numx[i-k]) == k && s[i-k] != 'B') 
            fs[i] = ((pow2[numx[i - k - 1]] - ts[i - k - 1]) + mod) % mod;
        ts[i] = (ts[i-1] * (1 + (s[i] == 'X')) + fs[i]) % mod;
    }
    numx[n+1] = numx[n];
    for (int i = n - k + 1; i >= 1; i--) {
        if (numw[i] - numw[i + k] + numx[i + k - 1] - numx[i - 1] == k && s[i + k] != 'W') 
            fr[i] = ((pow2[numx[n] - numx[i + k]] - tr[i + k + 1]) + mod) % mod;
        tr[i] = ( tr[i + 1] * (1 + (s[i] == 'X')) + fr[i] )  % mod;
         
    }
    long long ans = 0;
    //for (int i = 1; i <= n; i++) printf("%I64d ", ts[i]);
    for (int i = 1; i <= n; i++) ans = ((ans + fs[i] * tr[i + 1] % mod) + mod) % mod;
    printf("%I64d", ans);
    return 0;
}

具体细节有待进一步讨论
具体细节有待进一步讨论
具体细节有待进一步讨论
具体细节有待进一步讨论
rrd

T3:

正在写。。。

标题基于Python的自主学习系统后端设计与实现AI更换标题第1章引言介绍自主学习系统的研究背景、意义、现状以及本文的研究方法和创新点。1.1研究背景与意义阐述自主学习系统在教育技术领域的重要性和应用价值。1.2国内外研究现状分析国内外在自主学习系统后端技术方面的研究进展。1.3研究方法与创新点概述本文采用Python技术栈的设计方法和系统创新点。第2章相关理论与技术总结自主学习系统后端开发的相关理论和技术基础。2.1自主学习系统理论阐述自主学习系统的定义、特征和理论基础。2.2Python后端技术栈介绍DjangoFlask等Python后端框架及其适用场景。2.3数据库技术讨论关系型和非关系型数据库在系统中的应用方案。第3章系统设计与实现详细介绍自主学习系统后端的设计方案和实现过程。3.1系统架构设计提出基于微服务的系统架构设计方案。3.2核心模块设计详细说明用户管理、学习资源管理、进度跟踪等核心模块设计。3.3关键技术实现阐述个性化推荐算法、学习行为分析等关键技术的实现。第4章系统测试与评估对系统进行功能测试和性能评估。4.1测试环境与方法介绍测试环境配置和采用的测试方法。4.2功能测试结果展示各功能模块的测试结果和问题修复情况。4.3性能评估分析分析系统在高并发等场景下的性能表现。第5章结论与展望总结研究成果并提出未来改进方向。5.1研究结论概括系统设计的主要成果和技术创新。5.2未来展望指出系统局限性并提出后续优化方向。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值