zoukankan      html  css  js  c++  java
  • 2016 10 27 考试 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+1i这一段的天气已经全部被固定了,可以得出方案数有2^(1i-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:

    正在写。。。

  • 相关阅读:
    TSQL 基础学习 04
    第13章 网络编程
    Oracle 第一天
    第11章 进程与多线程
    Linux 第06天
    构造Json对象串工具类
    第14章 数据库
    第07章 集合
    YARNMR 大数据第二天
    第12章 多媒体
  • 原文地址:https://www.cnblogs.com/CtsNevermore/p/6005637.html
Copyright © 2011-2022 走看看