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 }
View Code

以上是关于10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解的主要内容,如果未能解决你的问题,请参考以下文章

10.1 国庆节给祖国母亲献礼 NOIP 模拟题 第三题 战争调度 题解

❤️中国万岁,提前祝福祖国母亲生日快乐❤️

数说(之四)·大话大数据技术之Hadoop(上)

我的国庆假期

C语言程序今天是祖国母亲的生日,特意编写一个小程序,为祖国母亲庆生~

十一模拟总结