zoukankan      html  css  js  c++  java
  • Nescafe #29 NOIP模拟赛

    Nescafe #29 NOIP模拟赛

      不知道这种题发出来算不算侵权...毕竟有的题在$bz$上是权限题,但是在$vijos$似乎又有原题...如果这算是侵权的话请联系我,我会尽快删除,谢谢~

      今天开始就处于一种半停课状态了.学校学习衡水,把休息时间压缩后每天又多了两节自习来写作业,但是我正好就可以来机房啦2333

      因为考试时间被文化课分割成了一些散块,这里就不区分考试时的代码和赛后补题了.

      

      T1:穿越七色虹

      题意概述:给出$x$轴上的$7$个圆(圆心和半径)(只保留$x$轴以上的部分),可以将所有圆的半径同时增加一个非负数,要求$(0,0)$到$(X_0,h)$这一块矩形面积被完全覆盖。

      其实这题读题稍微有点困难,不过概括之后就好理解多了。

      其实这题思路挺显然的,半径越大肯定覆盖的面积越大,所以直接二分这个扩大的值,扩大之后算出每个圆可以覆盖的高度为$h$的矩形的左右端点,再做一个线段覆盖即可.这里注意一个问题:$check$时会首先把每个半径加上一个数,最后再减掉,如果是这样的做法就一定要注意不能在函数进行到一半时就$return$掉,否则这个增量就会一直留在那里啦.

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cmath>
     4 # include <algorithm>
     5 
     6 using namespace std;
     7 
     8 const double eps=0.001;
     9 double h,x0;
    10 double x[8],rr[8],l,r,mid,ans;
    11 struct lin
    12 {
    13     double l,r;
    14 }a[8];
    15 
    16 bool check (double ad)
    17 {
    18     double maxr=0,minl=100000;
    19     for (int i=1;i<=7;++i)
    20     {
    21         a[i].l=x[i]-sqrt((rr[i]+ad)*(rr[i]+ad)-h*h);
    22         a[i].r=x[i]+sqrt((rr[i]+ad)*(rr[i]+ad)-h*h);
    23         minl=min(minl,a[i].l);
    24     }
    25     if(minl>eps) return false;
    26     for (int i=1;i<=7;++i)
    27         for (int j=1;j<=7;++j)
    28             if(a[j].l-maxr<=eps) maxr=max(maxr,a[j].r);
    29     if(maxr-x0>=-eps) return true;
    30     return false;
    31 }
    32 
    33 int main()
    34 {
    35     scanf("%lf%lf",&h,&x0);
    36     for (int i=1;i<=7;++i)
    37         scanf("%lf%lf",&x[i],&rr[i]);
    38     l=0,r=sqrt(x0*x0+h*h);
    39     ans=r+4;
    40     
    41     while (r-l>=-eps)
    42     {
    43         mid=(l+r)/2.0;
    44         if(check(mid))
    45             ans=min(ans,mid),r=mid-eps;
    46         else l=mid+eps;
    47     }
    48     printf("%.2lf",ans);
    49     return 0;
    50 }
    rainbow

      T2:四叶草魔杖

      题意概述:给出$n$个点$m$条边,每个点有一个能量值,如果是负的意味着要有这么多能量通过边运输过来,正的则为要运走这么多,每条边只要用到就会产生相应的代价,求使所有点的能量值都变为$0$所需要的最小代价.$n<=16$

      看到$n$这么小的范围当然会想到搜索状压$dp$.首先所有点都被连到一起必然是合法的,但是想要合法并不需要所有点都连在一起.首先一遍状压$dp$求出每个联通块联通的最小代价,统计一下哪些联通块的权值和是$0$,把这些状态单独拿出来再进行一次状压$dp$即可,虽然复杂度不是非常科学,但是跑的还是挺快的.

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # include <cstring>
     4 # define R register int
     5 
     6 using namespace std;
     7 
     8 const int maxn=16;
     9 const int maxz=(1<<16);
    10 int n,m,h,firs[maxn];
    11 int dp[maxz+5],a[maxn],x,y,co,j;
    12 struct edge
    13 {
    14     int too,nex,co;
    15 }g[maxn*maxn];
    16 int k[maxz+5],Top=0,c[maxz+5];
    17 
    18 void add (int x,int y,int co)
    19 {
    20     g[++h].co=co;
    21     g[h].nex=firs[x];
    22     firs[x]=h;
    23     g[h].too=y;
    24 }
    25 
    26 int main()
    27 {
    28     memset(dp,-1,sizeof(dp));
    29     dp[0]=0;
    30     scanf("%d%d",&n,&m);
    31     for (R i=0;i<n;++i)
    32         scanf("%d",&a[i]);
    33     for (R i=0;i<n;++i)
    34         dp[1<<i]=0;
    35     for (R i=1;i<=m;++i)
    36     {
    37         scanf("%d%d%d",&x,&y,&co);
    38         add(x,y,co);
    39         add(y,x,co);
    40     }
    41     for (R z=0;z<=(1<<n)-1;++z)
    42     {
    43         if(dp[z]==-1) continue;
    44         for (R i=0;i<n;++i)
    45         {
    46             if((z&(1<<i))==0) continue;
    47             for (R b=firs[i];b;b=g[b].nex)
    48             {
    49                 j=g[b].too;
    50                 if(z&(1<<j)) continue;
    51                 if(dp[z|(1<<j)]==-1)
    52                     dp[z|(1<<j)]=dp[z]+g[b].co;
    53                 else
    54                     dp[z|(1<<j)]=min(dp[z|(1<<j)],dp[z]+g[b].co);
    55             }
    56         }
    57     }
    58     for (R i=1;i<=(1<<n)-1;++i)
    59     {
    60         int s=0;
    61         if(dp[i]==-1) continue;
    62         for (R j=0;j<n;++j)
    63             if((1<<j)&i) s+=a[j];
    64         if(s==0) k[++Top]=i,c[Top]=dp[i];
    65     }
    66     memset(dp,-1,sizeof(dp));
    67     dp[0]=0;
    68     for (R i=0;i<=(1<<n)-1;++i)
    69     {
    70         if(dp[i]==-1) continue;
    71         for (R j=1;j<=Top;++j)
    72         {
    73             if(dp[ i|k[j] ]==-1) dp[ i|k[j] ]=dp[i]+c[j];
    74             else dp[ i|k[j] ]=min(dp[ i|k[j] ],dp[i]+c[j]);
    75         }
    76     }
    77     if(dp[(1<<n)-1]==-1) printf("Impossible");
    78     else printf("%d",dp[(1<<n)-1]);
    79     return 0;
    80 }
    clover

      T3:圣主的考验

      题意概述:定义一棵合法的二叉树为:每个点的左右儿子的高度差不大于$1$,求包含$n$个节点的树有多少种可能形态.$n<=3000$.注意:如果答案大于九位就输出后九位(包括前导零),如果小于九位就原样输出.

      朴素的$dp$不是很难想,但是是$n^3$的,现在在这个基础上考虑优化:(我又把$vscode$找出来啦,虽然编译的部分失效了,但是即使只是做文本编辑器也足够好看了)

      

      这个复杂度很显然是跑不满的,尤其是第二维,因为这道题的限制卡的比较严格,所以左右子树的节点数量大致上不会相差非常多,也就是说树高趋向于$log$级别.完全二叉树的深度是所有可能中最浅的,最深的深度也不会大很多,最极端的情况是每个左儿子都比右儿子的深度大,不过直接认为是$logi$加上一个小一点的数字也是可以的.如果发现一个多维$dp$的复杂度过高而明显跑不满时,可以将自己觉得最有可能跑不满的一维直接改小,比如这里的$j$直接改成$1-10$可以得到$90$.关于输出:打表发现当$n$大于等于$36$的时候答案会大于九位...

      
     1 # include <cstdio>
     2 # include <iostream>
     3 # define R register int
     4 # define mod 1000000000
     5 
     6 using namespace std;
     7 
     8 const int maxn=3005;
     9 int n,lg[maxn];
    10 long long dp[maxn][31],s[maxn];
    11 
    12 void init()
    13 {
    14     dp[0][0]=1;
    15     dp[1][1]=1;
    16     s[1]=1;
    17     for (R i=2;i<=3000;++i)
    18         for (R j=lg[i]+1;j<=lg[i]+5;++j)
    19         {
    20             for (R l=0;l<=i;++l)
    21             {
    22                 if(i-l-1<0) break;
    23                 dp[i][j]+=dp[l][j-1]*dp[i-l-1][j-2];
    24                 dp[i][j]%=mod;
    25                 dp[i][j]+=dp[l][j-2]*dp[i-l-1][j-1];
    26                 dp[i][j]%=mod;
    27                 dp[i][j]+=dp[l][j-1]*dp[i-l-1][j-1];
    28                 dp[i][j]%=mod;
    29             }
    30             s[i]+=dp[i][j];
    31             s[i]%=mod;
    32         }
    33 }
    34 
    35 int main()
    36 {
    37     scanf("%d",&n);
    38     for (R i=2;i<=3000;++i)
    39         lg[i]=lg[i/2]+1;
    40     init();
    41     while (n)
    42     {
    43         if(n>=36) printf("%09lld
    ",s[n]);
    44         else printf("%lld
    ",s[n]);
    45         scanf("%d",&n);    
    46     }
    47     return 0;
    48 }
    domine

    ---shzr

  • 相关阅读:
    【Node.js 自己封装的库 http_parse, libuv】
    select遍历list默认选中初始值
    mybatis入门基础----高级映射(一对一,一对多,多对多)
    工具类 | window批处理杀死指定端口进程
    eclipse 关闭控制台 自动弹出
    mybatis的jdbcType和javaType、oracle,MySQL的对应类型
    mysql 创建表格 AUTO_INCREMENT
    Linux shell脚本启动 停止 重启jar包
    Tomcat结合nginx使用小结
    集成maven和Spring boot的profile功能
  • 原文地址:https://www.cnblogs.com/shzr/p/9763232.html
Copyright © 2011-2022 走看看