10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解相关的知识,希望对你有一定的参考价值。
这道题可以说是这次考试最有意思,最成功,也是最失败的了。
当时看完题首先打了O(2^(2^n))的大暴力,管他正解是啥,保分再说。
然后想到了状压,对于每一个平民状压的话果断扑街啊,时间空间双爆炸,双爆炸……
然后就开始想,当时由于第一题费的时间有一点多,然而由于几乎认定第二题我不会(我是不是太消极了),果断尽可能把时间给到第三道题上来,这道题也就获得了一个半小时的时间,也算宽裕。我开始打正解时大概还剩一个小时的时间。
状压平民行不通,就开始在大脑中bfs,根据这道题的树的特性,我们好像可以用一下树归,呃,树归?接着由于m的限制。就开始想出了一下状态数组:
dp[i][j]表示在i节点上有j个平民打仗的最优解,然后发现根本行不通的说,我无法知道下面的平民谁在去打仗,无法转移。(剧透一波,这其实就是正确答案)。
然后思路又回到了状压上,n<=10,虽然是层数,但不得不说还是挺小的,这有什么玄机吗?
然后我发现每一个平民是否参战只与他的上司有关,而我貌似可以状压一波该点所有上司的状态再在树上转移。然后先分析了一下空间复杂度,第一维得是点,第二维是状态,第三维还得去限制m。这就很有意思了,本来看似完美的正解M掉了……
然后我又想了一下数据范围,n<=8,貌似刚好是这种打法的M上限,还真是特意为这种打法准备的啊,谢谢出题人全家……
没办法,还有一个小时不到,能拿多少分是多少分,先打了吧。然后打了没多久才想起来去算时间复杂度,然后发现,理论貌似要42秒多……不管了,能拿一分是一分,干他,斯巴达!
于是乎用了不到半个小时连打带调搞完了状压,提交上去50分,数据水的可以……
下面说正解。
其实我想的基本上没太大错,状压+树归,只不过我当初是被内存限制住了手脚,其实我们完全可以一边DFS这一棵树一边把父节点们的状态传下来,然后M就可以完美的解决掉了。那么状态方程也就是我上面提到过的dp[i][j],因为到了叶节点时由于父亲的状态都知道,完全可以直接求出所有贡献,我们转移时只要枚举左儿子选了几个就好了。至于时间复杂度吗?只能说和m有极大关联,不过貌似跑的还是挺快的,只能说明m相当小……
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 #include <algorithm> 7 #include <cmath> 8 #include <map> 9 #include <set> 10 #define N 1024 11 using namespace std; 12 int n,m,w[N][N],f[N][N],l[N],r[N]; 13 long long ans; 14 long long dp[N][N]; 15 int deep[N]; 16 void dfs2(int x,int zt) 17 { 18 memset(dp[x],0,sizeof(dp[x])); 19 if(x<(1<<(n-1))) 20 { 21 dfs2(x*2,zt<<1); 22 dfs2(x*2+1,zt<<1); 23 int to=min(m,r[x]-l[x]+1); 24 for(int i=0;i<=to;i++) 25 { 26 int tt=min(i,r[x*2]-l[x*2]+1); 27 for(int j=0;j<=tt;j++) 28 { 29 if(dp[x][i]<dp[x*2][j]+dp[x*2+1][i-j]) 30 dp[x][i]=dp[x*2][j]+dp[x*2+1][i-j]; 31 } 32 } 33 dfs2(x*2,(zt<<1)|1); 34 dfs2(x*2+1,(zt<<1)|1); 35 for(int i=0;i<=to;i++) 36 { 37 int tt=min(i,r[x*2]-l[x*2]+1); 38 for(int j=0;j<=tt;j++) 39 { 40 if(dp[x][i]<dp[x*2][j]+dp[x*2+1][i-j]) 41 dp[x][i]=dp[x*2][j]+dp[x*2+1][i-j]; 42 } 43 } 44 return; 45 } 46 else 47 { 48 int now=x,t=-1; 49 while(now!=1) 50 { 51 now/=2; 52 t++; 53 if(zt&(1<<t)) 54 dp[x][1]+=w[x][now]; 55 else 56 dp[x][0]+=f[x][now]; 57 } 58 return; 59 } 60 } 61 void work2() 62 { 63 dfs2(1,0); 64 for(int i=0;i<=m;i++) 65 ans=max(ans,dp[1][i]); 66 printf("%lld\\n",ans); 67 } 68 int main() 69 { 70 scanf("%d%d",&n,&m); 71 for(int i=1;i<=(1<<(n-1));i++) 72 { 73 int x=((1<<(n-1))+i-1),to; 74 to=x; 75 l[x]=r[x]=x; 76 for(int j=1;j<n;j++) 77 { 78 to/=2; 79 scanf("%d",&w[x][to]); 80 w[to][x]=w[x][to]; 81 } 82 } 83 for(int i=1;i<=(1<<(n-1));i++) 84 { 85 int x=((1<<(n-1))+i-1),to; 86 to=x; 87 for(int j=1;j<n;j++) 88 { 89 to/=2; 90 scanf("%d",&f[x][to]); 91 } 92 } 93 int nw=1; 94 for(int i=1;i<(1<<n);i++) 95 { 96 if(i<(1<<nw)) 97 deep[i]=nw; 98 else 99 { 100 nw++; 101 deep[i]=nw; 102 } 103 } 104 for(int i=((1<<(n-1))-1);i>0;i--) 105 { 106 l[i]=l[i*2]; 107 r[i]=r[i*2+1]; 108 } 109 work2(); 110 return 0; 111 }
以上是关于10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解的主要内容,如果未能解决你的问题,请参考以下文章
10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解