zoukankan      html  css  js  c++  java
  • 2018.8.6 Noip2018模拟测试赛(十九)

    日期:

    八月六号

     总分:

    300分

     难度:

    提高 ~ 省选  

     得分:

    10分(MMP)

    题目目录:

      T1:Tree

      T2:异或运算

      T3:Tree Restoring

    赛后反思:

    Emmmmmmm……

    一直在打第一题…… 结果考完才发现dp少了一种情况……

    除此之外,我无话可说…… Emmmmmm……

    题解:

    T1:Tree

    树形背包dp,设$f[i][j][k(0/1/2)]$为$i$的子树中,选$j$条边,0:从$i$出发,到$i$结束/1:从$i$出发,到$i$的某个后代结束/2:后代开始,经过$i$,后代结束:

    状态转移:

    1 f[x][j+k+1][0]=min(f[x][j+k+1][0],f[x][j][0]+f[y][k][0]+2*e[i].dis);
    2 f[x][j+k+1][1]=min(f[x][j+k+1][1],f[x][j][0]+f[y][k][1]+e[i].dis);
    3 f[x][j+k+1][1]=min(f[x][j+k+1][1],f[x][j][1]+f[y][k][0]+2*e[i].dis);
    4 f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][1]+f[y][k][1]+e[i].dis);
    5 f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][0]+f[y][k][2]+2*e[i].dis);
    6 f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][2]+f[y][k][0]+2*e[i].dis);

    这样就能树形dp,时间复杂度 $O(n^2)$

    COMPLETE CODE:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 
     6 int n,k,x,y,z,tot=0,h[3005],siz[3005];
     7 long long f[3005][3005][3],ans=1e18;
     8 struct Edge{
     9     int x,y,dis,next;
    10 }e[6005];
    11 bool vis[3005];
    12 
    13 inline void add_edge(int x,int y,int z){
    14     e[++tot].x=y,e[tot].dis=z;
    15     e[tot].next=h[x],h[x]=tot;
    16 }
    17 
    18 void dfs(int x,int fa){
    19     siz[x]=1;
    20     f[x][0][0]=0;    
    21     f[x][0][1]=0;
    22     for(int i=h[x];i;i=e[i].next){
    23         if(e[i].x==fa)continue;
    24         dfs(e[i].x,x);
    25         int y=e[i].x;
    26         for(int j=siz[x]-1;j>=0;j--)
    27         for(int k=siz[y]-1;k>=0;k--){
    28             f[x][j+k+1][0]=min(f[x][j+k+1][0],f[x][j][0]+f[y][k][0]+2*e[i].dis);
    29             f[x][j+k+1][1]=min(f[x][j+k+1][1],f[x][j][0]+f[y][k][1]+e[i].dis);
    30             f[x][j+k+1][1]=min(f[x][j+k+1][1],f[x][j][1]+f[y][k][0]+2*e[i].dis);
    31             f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][1]+f[y][k][1]+e[i].dis);
    32             f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][0]+f[y][k][2]+2*e[i].dis);
    33             f[x][j+k+1][2]=min(f[x][j+k+1][2],f[x][j][2]+f[y][k][0]+2*e[i].dis);
    34         }
    35         siz[x]+=siz[e[i].x];
    36     }
    37 }
    38 
    39 int main(){
    40     memset(f,0x7f,sizeof(f));
    41     scanf("%d%d",&n,&k);
    42     for(int i=1;i<n;i++){
    43         scanf("%d%d%d",&x,&y,&z);
    44         add_edge(x,y,z);
    45         add_edge(y,x,z);
    46     }
    47     dfs(1,-1);
    48     for(int i=1;i<=n;i++)
    49         ans=min(ans,min(f[i][k-1][1],f[i][k-1][2]));
    50     printf("%lld",ans);
    51 }

    T2:异或运算

    可持久化Trie树,我之前还不知道可持久化,现在才知道,这跟主席树是一样的,是通过差分,维护区间。

    我们按位贪心,由于$n$很小,对于每一位枚举$a$序列,统计现在的位置往优了走会有多少个值,如果大于$k$,可以走,如果小于$k$,所有反着走。

    问题就这么迎刃而解了。(貌似这题用动态开点的主席树维护值域也能做……)

    CODE:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 int n,m,q,x,y,l,r,k,cnt=0,tot=0;
     6 int a[1005],b[300005],root[300005];
     7 struct Trie{
     8     int siz,next[2];
     9 }v[20000005];
    10 struct Node{
    11     int l,r,val;
    12 }s[300005];
    13 
    14 void insert(int &o,int last,int x){
    15     o=++tot;
    16     int p=o,q=last;
    17     for(int i=31;i>=0;i--){
    18         v[p]=v[q],v[p].siz++;
    19         v[p].next[(x>>i)&1]=++tot;
    20         p=v[p].next[(x>>i)&1];
    21         q=v[q].next[(x>>i)&1];
    22     }
    23     v[p].siz++;
    24 }
    25 
    26 int find(int cnt,int k){
    27     int ans=0;
    28     for(int i=31;i>=0;i--){
    29         int sum=0;
    30         for(int j=1;j<=cnt;j++){
    31             bool c=(s[j].val>>i)&1;
    32             sum+=v[v[s[j].r].next[c^1]].siz
    33                 -v[v[s[j].l].next[c^1]].siz;
    34         }
    35         if(sum>=k){
    36             ans=ans<<1|1;
    37             for(int j=1;j<=cnt;j++){
    38                 bool c=(s[j].val>>i)&1;
    39                 s[j].r=v[s[j].r].next[c^1];
    40                 s[j].l=v[s[j].l].next[c^1];
    41             }
    42         }else{
    43             k-=sum,ans=ans<<1;
    44             for(int j=1;j<=cnt;j++){
    45                 bool c=(s[j].val>>i)&1;
    46                 s[j].r=v[s[j].r].next[c];
    47                 s[j].l=v[s[j].l].next[c];
    48             }
    49         }
    50     }
    51     return ans;
    52 }
    53 
    54 int main(){
    55     scanf("%d%d",&n,&m);
    56     for(int i=1;i<=n;i++)scanf("%d",a+i);
    57     for(int i=1;i<=m;i++)scanf("%d",b+i);
    58     for(int i=1;i<=m;i++)
    59         insert(root[i],root[i-1],b[i]);
    60     scanf("%d",&q);
    61     for(int i=1;i<=q;i++){
    62         scanf("%d%d%d%d%d",&x,&y,&l,&r,&k);
    63         cnt=0;
    64         for(int j=x;j<=y;j++)
    65             s[++cnt]=(Node){root[l-1],root[r],a[j]};
    66         printf("%d
    ",find(cnt,k));
    67     }
    68 }

    T3:Tree Restoring

    很容易发现离所有点最远的点定是树的直径的两个端点。(我怎么就没想到呢?)

    所有点的距离只能在$leftlceil{dover 2} ight ceil$到$d$之间,同时直径上的点两两对称,判断这些即可。

    CODE:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 using namespace std;
     5 
     6 int n,x,a,b,t[105];
     7 
     8 int main(){
     9     scanf("%d",&n);
    10     for(int i=1;i<=n;i++){
    11         scanf("%d",&x);
    12         t[x]++,a=max(a,x);
    13     }
    14     b=a+1>>1;
    15     for(int i=b+1;i<=a;i++)
    16         if(t[i]<2){
    17             printf("Impossible");
    18             return 0;
    19         }
    20     if(a&1){
    21         if(t[b]<2){
    22             printf("Impossible");
    23             return 0;
    24         }t[b]-=2;
    25     }else{
    26         if(t[b]<1){
    27             printf("Impossible");
    28             return 0;
    29         }t[b]-=1;
    30     }
    31     for(int i=1;i<=b;i++)
    32         if(t[i]){
    33             printf("Impossible");
    34             return 0;
    35         }
    36     printf("Possible");
    37 }
  • 相关阅读:
    数据挖掘——统计学分析(五:统计量)
    数据挖掘——统计学分析(四:概率与概率分布)
    linux shell之sed
    ListView常用属性 (2012-01-12 17:20:27)
    android ListView几个比较特别的属性
    android
    android:layout_weight的真实含义
    linux下mysql安装、目录结构、配置
    mysql查看数据库和表的占用空间大小
    Android实战技巧:如何在ScrollView中嵌套ListView
  • 原文地址:https://www.cnblogs.com/ezoiLZH/p/9431956.html
Copyright © 2011-2022 走看看