• 2015 Multi-University Training Contest 3


    1001 Magician

    线段树。根据奇偶性分成4个区间。维护子列和最大值。

    想法很简单。但是并不好写。

    首先初始化的时候对于不存在的点要写成-INF。

    然后pushup的时候。对于每个区间要考虑四个情况。

    例如sum01。

    他可能是左子树的sum01右子树的sum01。

    或者左子树的sum01+右子树的sum01。

    或者左子树的sum00+右子树的sum11。

    最后注意query函数的写法。

    如果在递归的时候就讨论奇偶性。

    下层的每个区间都要被重复调用。而且是层数的指数级。

    于是参考学习了一种直接把子区间合并成一个区间类型返回的方法。

    合成目标区间后再讨论奇偶性。

    【其实pushup和query可以写好看些。好不容易调对。懒得改了。】

      1 # include <iostream>
      2 # include <cstdio>
      3 # include <algorithm>
      4 using namespace std;
      5 typedef long long LL;
      6 # define maxn 100010
      7 # define INF (LL)1000000000000
      8 LL a[maxn];
      9 
     10 struct node
     11 {
     12     int l,r;
     13     LL sum00,sum01,sum10,sum11;
     14 }tree[4*maxn];
     15 
     16 void pushup(int i)
     17 {
     18     tree[i].sum00=tree[i].sum01=tree[i].sum10=tree[i].sum11=-INF;
     19     tree[i].sum00=max(tree[i].sum00,tree[2*i].sum00+tree[2*i+1].sum10);
     20     tree[i].sum00=max(tree[i].sum00,tree[2*i].sum01+tree[2*i+1].sum00);
     21     tree[i].sum00=max(tree[i].sum00,tree[2*i].sum00);
     22     tree[i].sum00=max(tree[i].sum00,tree[2*i+1].sum00);
     23     tree[i].sum01=max(tree[i].sum01,tree[2*i].sum00+tree[2*i+1].sum11);
     24     tree[i].sum01=max(tree[i].sum01,tree[2*i].sum01+tree[2*i+1].sum01);
     25     tree[i].sum01=max(tree[i].sum01,tree[2*i].sum01);
     26     tree[i].sum01=max(tree[i].sum01,tree[2*i+1].sum01);
     27     tree[i].sum10=max(tree[i].sum10,tree[2*i].sum10+tree[2*i+1].sum10);
     28     tree[i].sum10=max(tree[i].sum10,tree[2*i].sum11+tree[2*i+1].sum00);
     29     tree[i].sum10=max(tree[i].sum10,tree[2*i].sum10);
     30     tree[i].sum10=max(tree[i].sum10,tree[2*i+1].sum10);
     31     tree[i].sum11=max(tree[i].sum11,tree[2*i].sum10+tree[2*i+1].sum11);
     32     tree[i].sum11=max(tree[i].sum11,tree[2*i].sum11+tree[2*i+1].sum01);
     33     tree[i].sum11=max(tree[i].sum11,tree[2*i].sum11);
     34     tree[i].sum11=max(tree[i].sum11,tree[2*i+1].sum11);
     35     return;
     36 }
     37 
     38 void buildtree(int i,int l,int r)
     39 {
     40     tree[i].l=l; tree[i].r=r;
     41     if(l<r)
     42     {
     43         buildtree(2*i,l,(l+r)/2);
     44         buildtree(2*i+1,(l+r)/2+1,r);
     45         pushup(i);
     46     }
     47     else
     48     {
     49         if(l%2)
     50         {
     51             tree[i].sum11=a[l];
     52             tree[i].sum10=tree[i].sum01=tree[i].sum00=-INF;
     53         }
     54         else
     55         {
     56             tree[i].sum00=a[l];
     57             tree[i].sum10=tree[i].sum01=tree[i].sum11=-INF;
     58         }
     59     }
     60     return;
     61 }
     62 
     63 void update(int i,int p,int v)
     64 {
     65     if(tree[i].l==tree[i].r)
     66     {
     67         if(p%2) tree[i].sum11=v;
     68         else tree[i].sum00=v;
     69     }
     70     else
     71     {
     72         if(p<=(tree[i].l+tree[i].r)/2) update(2*i,p,v);
     73         else update(2*i+1,p,v);
     74         pushup(i);
     75     }
     76     return;
     77 }
     78 
     79 node query(int i,int l,int r)
     80 {
     81     if(tree[i].l>=l&&tree[i].r<=r) return tree[i];
     82     if(r<=(tree[i].l+tree[i].r)/2) return query(2*i,l,r);
     83     if(l>=(tree[i].l+tree[i].r)/2+1) return query(2*i+1,l,r);
     84     node t,t1,t2;
     85     t1=query(2*i,l,r);
     86     t2=query(2*i+1,l,r);
     87     t.sum00=max(t1.sum00,t2.sum00);
     88     t.sum00=max(t.sum00,t1.sum00+t2.sum10);
     89     t.sum00=max(t.sum00,t1.sum01+t2.sum00);
     90     t.sum01=max(t1.sum01,t2.sum01);
     91     t.sum01=max(t.sum01,t1.sum00+t2.sum11);
     92     t.sum01=max(t.sum01,t1.sum01+t2.sum01);
     93     t.sum10=max(t1.sum10,t2.sum10);
     94     t.sum10=max(t.sum10,t1.sum10+t2.sum10);
     95     t.sum10=max(t.sum10,t1.sum11+t2.sum00);
     96     t.sum11=max(t1.sum11,t2.sum11);
     97     t.sum11=max(t.sum11,t1.sum10+t2.sum11);
     98     t.sum11=max(t.sum11,t1.sum11+t2.sum01);
     99     return t;
    100 }
    101 
    102 int main(void)
    103 {
    104     int T; cin>>T;
    105     while(T--)
    106     {
    107         int n,m; scanf("%d%d",&n,&m);
    108         for(int i=1;i<=n;i++) scanf("%I64d",a+i);
    109         buildtree(1,1,n);
    110         while(m--)
    111         {
    112             int type,x,y; scanf("%d%d%d",&type,&x,&y);
    113             if(type) update(1,x,y);
    114             else
    115             {
    116                 node tem=query(1,x,y);
    117                 LL ans=-INF;
    118                 ans=max(ans,tem.sum00);
    119                 ans=max(ans,tem.sum01);
    120                 ans=max(ans,tem.sum10);
    121                 ans=max(ans,tem.sum11);
    122                 printf("%I64d
    ",ans);
    123             }
    124         }    
    125     }
    126     return 0;
    127 }
    Aguin

    1002 RGCDQ

    先枚举1000000内所有质因数。

    然后统计区间内每个数的质因数个数。

    注意到最大只有7。

    对于因子个数为1-7的数的个数处理一下前缀和。

    对于每个询问。算区间内因子数分别为1-7的数的个数。

    找到最大的gcd就是答案。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 # include <vector>
     6 using namespace std;
     7 # define maxn 1000010    
     8 bool tag[maxn]={1,1};
     9 int prime[42000],cnt[maxn]={0},presum[8][maxn]={0};
    10 
    11 int main(void)
    12 {
    13     int t=0;
    14     for(int i=2;i<maxn/2;i++)
    15     {
    16         if(!tag[i]) prime[++t]=i;
    17         for(int j=1;j<=t&&i*prime[j]<maxn;j++)
    18         {
    19             tag[i*prime[j]]=1;
    20             if(i%prime[j]==0) break;
    21         }
    22     }
    23     for(int i=1;i<=t;i++)
    24         for(int j=1;prime[i]*j<=maxn;j++)
    25             cnt[prime[i]*j]++;
    26     for(int i=1;i<=maxn;i++)
    27         for(int j=1;j<=7;j++)
    28         {
    29             presum[j][i]=presum[j][i-1];
    30             if(cnt[i]==j) presum[j][i]++;
    31         }
    32     int T; cin>>T;
    33     while(T--)
    34     {
    35         int l,r; scanf("%d%d",&l,&r);
    36         int mark[8]={0};
    37         for(int i=1;i<8;i++) mark[i]=max(0,presum[i][r]-presum[i][l-1]);
    38         if(mark[7]>=2) printf("7
    ");
    39         else if(mark[6]>=2) printf("6
    ");
    40         else if(mark[5]>=2) printf("5
    ");
    41         else if(mark[4]>=2) printf("4
    ");
    42         else if(mark[3]>=2||mark[3]&&mark[6]) printf("3
    ");
    43         else if(mark[2]>=2||mark[2]&&mark[4]||mark[2]&&mark[6]) printf("2
    ");
    44         else printf("1
    ");
    45     }
    46     return 0;   
    47 }
    Aguin

    1003 The Goddess Of The Moon

    1004 Painter

    看成R和B的两张图。

    统计R斜边上与B/斜边上的连续染色段数即为答案。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 using namespace std;
     5 # define CLR(x) memset(x,0,sizeof(x)) 
     6 char map[55][55];
     7 int R[55][55],B[55][55];
     8 
     9 int main(void)
    10 {
    11     int T; cin>>T;
    12     while(T--)
    13     {
    14         CLR(map); CLR(R); CLR(B);
    15         int n; scanf("%d",&n);
    16         for(int i=0;i<n;i++) scanf("%s",map[i]);
    17         int len=strlen(map[0]);
    18         for(int i=0;i<n;i++)
    19             for(int j=0;j<len;j++)
    20             {
    21                 if(map[i][j]=='R') R[i][j]=1;
    22                 else if(map[i][j]=='B') B[i][j]=1;
    23                 else if(map[i][j]=='G') R[i][j]=B[i][j]=1;
    24             }
    25         int ans=0;
    26         for(int i=1-n;i<len;i++)
    27         {
    28             int flag=0;
    29             for(int j=0;j<n&&i+j<len;j++)
    30             {
    31                 if(i+j<0) continue;
    32                 if(!flag&&R[j][i+j]) {ans++;flag=1;}
    33                 if(!R[j][i+j]) flag=0;
    34             }
    35         }
    36         for(int i=0;i<n+len-1;i++)
    37         {
    38             int flag=0;
    39             for(int j=0;j<len&&i-j>=0;j++)
    40             {
    41                 if(i-j>=n) continue;
    42                 if(!flag&&B[i-j][j]) {ans++;flag=1;}
    43                 if(!B[i-j][j]) flag=0;
    44             }
    45         }
    46         printf("%d
    ",ans);
    47     }
    48     return 0;
    49 }
    Aguin

    1005 Fan Li

    1006 Beautiful Set

    1007 Hope

    1008 Solve this interesting problem

    暴搜可行 证明不会。

    l<0跳。l>r-l跳。r>现有答案跳。

    搜[l,2*r-l]的时候注意死循环。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <algorithm>
     4 using namespace std;
     5 typedef long long LL;
     6 LL ans;
     7 
     8 void dfs(LL l,LL r)
     9 {
    10     if(l==0)
    11     {
    12         if(ans==-1) ans=r;
    13         else ans=min(ans,r);
    14         return;
    15     }
    16     if(l<0) return;
    17     if(ans!=-1&&r>=ans) return;
    18     if(r>2*l) return;
    19     if(r>l) dfs(l,2*r-l);
    20     dfs(2*l-r-1,r);
    21     dfs(2*l-r-2,r);
    22     dfs(l,2*r-l+1);
    23     return;
    24 }
    25 
    26 int main(void)
    27 {
    28     LL l,r;
    29     while((scanf("%I64d%I64d",&l,&r))!=EOF)
    30     {
    31         ans=-1;
    32         dfs(l,r);
    33         printf("%I64d
    ",ans);
    34     }
    35     return 0;
    36 }
    Aguin

    1009 Boring Class

    1010 Crazy Bobo

    按官方题解。

    把每条边变成从w大的点到w小的点的有像边。 

    以u为min的目标集就是能走到u的点的集合。

    花了较长的时间思考这个问题。

    换一种说法。

    其实就是对于一个已经确定最小值u的目标集S。

    点v在S中当且仅当v能通过递减的路到达u。

    简要说明一下必要性和充分性。

    随手画了个图。

    任意取一条链。比方X。它必然有一个端点x1。

    只要说明离x1最近的点x2小于x1。然后考虑去掉x1的图。归纳即可得到上述结论。

    考虑S中比x1小的最大的点p的位置。

    如果x2就是p。那么它比x1小。

    如果x2不是p。那么由于x2离x1最近。无论p在什么位置。x2都在p-x1的链上。

    根据S的定义。x2小于x1。

    反之。如果所有链都是以递减的顺序通向u的。

    那么考虑图中的最大点。其必然在一条链的端点。

    比方仍取X链。x1是最大点。

    最大点给集合带来的约束条件只有一条。

    那就是最大点到次大点的路径上的所有点小于最大点。

    但是所有点都小于最大点。所以这个条件必然成立。

    也就是说原来的点属于S集等价于去掉最大点后的所有点属于S集合。

    而去掉x1后的最大点可能是x2或者是其他链的端点。

    只要不断从端点去掉最大点。归纳即可证明原来的所有点属于S集。

    证明这个之后。树dp即可。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <algorithm>
     5 # include <vector>
     6 using namespace std;
     7 # define maxn 500050
     8 int w[maxn],dp[maxn];
     9 vector<int> edge[maxn];
    10 
    11 struct V
    12 {
    13     int id,w;
    14 } node[maxn];
    15 
    16 bool cmp(V a,V b)
    17 {
    18     return a.w>b.w;
    19 }
    20 
    21 int main(void)
    22 {
    23     int n;
    24     while((scanf("%d",&n))!=EOF)
    25     {
    26         memset(edge,0,sizeof(edge));
    27         for(int i=1;i<=n;i++)
    28         {
    29             scanf("%d",w+i);
    30             node[i].id=i;
    31             node[i].w=w[i];
    32         }
    33         for(int i=1;i<n;i++)
    34         {
    35             int a,b; scanf("%d%d",&a,&b);
    36             if(w[a]>w[b]) edge[b].push_back(a);
    37             else if(w[a]<w[b]) edge[a].push_back(b);
    38         }
    39         sort(node+1,node+1+n,cmp);
    40         int ans=0;
    41         for(int i=1;i<=n;i++)
    42         {
    43             int pos=node[i].id;
    44             dp[pos]=1;
    45             for(int j=0;j<edge[pos].size();j++)
    46                 dp[pos]+=dp[edge[pos][j]];
    47             ans=max(dp[pos],ans);
    48         }
    49         printf("%d
    ",ans);
    50     }
    51     return 0;
    52 }
    Aguin

    1011 Work

    签到题。dfs一遍即可。

     1 # include <iostream>
     2 # include <cstdio>
     3 # include <cstring>
     4 # include <vector>
     5 using namespace std;
     6 int ind[105],cnt[105];
     7 vector <int> edge[105];
     8 
     9 void dfs(int x)
    10 {
    11     cnt[x]=edge[x].size();
    12     for(int i=0;i<edge[x].size();i++)
    13     {
    14         dfs(edge[x][i]);
    15         cnt[x]+=cnt[edge[x][i]];
    16     }
    17     return;
    18 }
    19 
    20 int main(void)
    21 {
    22     int n,k;
    23     while((scanf("%d%d",&n,&k))!=EOF)
    24     {
    25         memset(ind,0,sizeof(ind));
    26         memset(cnt,0,sizeof(cnt));
    27         for(int i=1;i<=n;i++) edge[i].clear();
    28         for(int i=1;i<n;i++)
    29         {
    30             int u,v; scanf("%d%d",&u,&v);
    31             edge[u].push_back(v);
    32             ind[v]++;
    33         }
    34         for(int i=1;i<=n;i++) if(!ind[i]) dfs(i);
    35         int ans=0;
    36         for(int i=1;i<=n;i++) if(cnt[i]==k) ans++;
    37         printf("%d
    ",ans);
    38     }
    39     return 0;
    40 }
    Aguin
  • 相关阅读:
    springboot接口测试
    谷粒学院_day08_课程管理_添加课程之课程发布(后端开发)
    谷粒学院_day03_vue组件
    谷粒学院_day03_vue固定代码抽取
    vue自定义事件
    vue插槽slot
    vue基本语法
    Vue之axios异步通信
    无归岛[HNOI2009]
    仓库建设[ZJOI2007]
  • 原文地址:https://www.cnblogs.com/Aguin/p/4683494.html
Copyright © 2020-2023  润新知