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\n",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\n");
39         else if(mark[6]>=2) printf("6\n");
40         else if(mark[5]>=2) printf("5\n");
41         else if(mark[4]>=2) printf("4\n");
42         else if(mark[3]>=2||mark[3]&&mark[6]) printf("3\n");
43         else if(mark[2]>=2||mark[2]&&mark[4]||mark[2]&&mark[6]) printf("2\n");
44         else printf("1\n");
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\n",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\n",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\n",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\n",ans);
38     }
39     return 0;
40 }
Aguin

 

posted @ 2015-07-28 17:15  Aguin  阅读(282)  评论(0编辑  收藏  举报