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:

    正在写。。。

  • 相关阅读:
    How To Build CyanogenMod Android for smartphone
    CentOS安装Code::Blocks
    How to Dual boot Multiple ROMs on Your Android SmartPhone (Upto Five Roms)?
    Audacious——Linux音乐播放器
    How to Dual Boot Multiple ROMs on Your Android Phone
    Everything You Need to Know About Rooting Your Android Phone
    How to Flash a ROM to Your Android Phone
    什么是NANDroid,如何加载NANDroid备份?
    Have you considered compiled a batman-adv.ko for android?
    BATMAN—Better Approach To Mobile Adhoc Networking (B.A.T.M.A.N.)
  • 原文地址:https://www.cnblogs.com/CtsNevermore/p/6005637.html
Copyright © 2011-2022 走看看