2013 Multi-University Training Contest 8 部分解题报告

problem  1001  (hdu 4676)

Sum Of Gcd

思路:数论问题,gcd(a[i],a[j])一定等于a[i]的某个约数,那么我们就可以枚举a[i]的约数,每个约数在该区间出现的次数,即用该约数*次数,,可得到所求,

但是很重要的一点就是,举例a[i]=8来说,枚举4、2、1,当到4的时候,又需要枚举2,1,那么就会重复计算所以让f(8)+f(4)+f(2)+f(1)=8,可以得到f(n)是欧拉函数,所以可以利用欧拉函数去重,,,,,询问的处理则用分块处理

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<stdlib.h>
  6 #include<queue>
  7 #include<stack>
  8 #include<vector>
  9 #include<cmath>
 10 #define LL __int64
 11 using namespace std;
 12 const int maxn=20010;
 13 int a[maxn];
 14 int phi[maxn];
 15 LL ans[maxn];
 16 int num[maxn];
 17 vector<int>vec[maxn];
 18 struct node
 19 {
 20     int l,r;
 21     int id;
 22 } que[maxn];
 23 int M;
 24 bool cmp(struct node a,struct node b)
 25 {
 26     int aa=a.l/M;
 27     int bb=b.l/M;
 28     if(aa!=bb)
 29         return aa<bb;
 30     return a.r<b.r;
 31 }
 32 void init()
 33 {
 34     int i,j;
 35     vec[0].clear();
 36     for(i=1; i<maxn; i++)
 37     {
 38         phi[i]=i;
 39     }
 40     for(i=2; i<maxn; i++)
 41     {
 42         if(phi[i]==i)
 43         {
 44             for(j=i; j<maxn; j+=i)
 45                 phi[j]=phi[j]/i*(i-1);//欧拉函数
 46         }
 47 
 48     }
 49     for(i=1; i<maxn; i++)
 50     {
 51         for(j=i; j<maxn; j+=i)
 52         {
 53             vec[j].push_back(i);//记录j的约数
 54         }
 55     }
 56 }
 57 LL run1(int x)//删除
 58 {
 59     int i;
 60     LL res=0;
 61     for(i=0; i<vec[x].size(); i++)
 62     {
 63         num[vec[x][i]]--;
 64         res+=phi[vec[x][i]]*num[vec[x][i]];
 65     }
 66     return res;
 67 }
 68 LL run2(int x)//增加
 69 {
 70     int i;
 71     LL res=0;
 72     for(i=0; i<vec[x].size(); i++)
 73     {
 74         res+=phi[vec[x][i]]*num[vec[x][i]];
 75         num[vec[x][i]]++;
 76     }
 77     return res;
 78 }
 79 void query(int m)
 80 {
 81     int i;
 82     memset(num,0,sizeof(num));//记录约数影响的数量
 83     LL res=0;
 84     int l=0,r=0;
 85     for(i=1; i<=m; i++)
 86     {
 87         int li=que[i].l;
 88         int ri=que[i].r;
 89         while(li<l)
 90         {
 91             l--;
 92             res+=run2(a[l]);
 93 
 94         }
 95         while(li>l)
 96         {
 97             res-=run1(a[l]);
 98             l++;
 99         }
100         while(ri>r)
101         {
102             r++;
103             res+=run2(a[r]);
104 
105         }
106         while(ri<r)
107         {
108             res-=run1(a[r]);
109             r--;
110         }
111         ans[que[i].id]=res;
112     }
113 }
114 int main()
115 {
116     int T,K=0;
117     init();
118     scanf("%d",&T);
119     while(T--)
120     {
121         int n;
122         int i;
123         K++;
124         scanf("%d",&n);
125         a[0]=0;
126         for(i=1; i<=n; i++)
127             scanf("%d",&a[i]);
128         int m;
129         scanf("%d",&m);
130         for(i=1; i<=m; i++)
131         {
132             scanf("%d%d",&que[i].l,&que[i].r);
133             que[i].id=i;
134         }
135         M=(int)sqrt(n*1.0);
136         sort(que+1,que+m+1,cmp);//分块排序
137         query(m);
138         printf("Case #%d:\n",K);
139         for(i=1; i<=m; i++)
140         {
141             printf("%I64d\n",ans[i]);
142         }
143     }
144     return 0;
145 }
View Code

 

 

problem  1003  (hdu 4678)

Mine

思路:博弈,,把没有数字的格全部联通,周围包括的有数字的点数为偶数的我们称为偶圈,有奇数个数字点数的圈称为奇圈,

        我们可以知道偶圈是不能改变命运的(即谁先点的谁就可以操控让自己最后点)如果是奇圈的话则可以改变命运(即不能操控自己是最后一个点的)

        所以我们可以看到偶圈相当于一个数字,如果是奇数个奇圈的话那么第一个点的一定会赢,要是数字的个数和偶圈的个数是奇数的话那么第一个人肯定赢

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<stack>
  7 #pragma comment(linker, "/STACK:1024000000,1024000000")
  8 const int maxn=1010;
  9 int map[maxn][maxn];
 10 bool vis[maxn][maxn];
 11 int dirx[8]= {1,1,1,-1,-1,-1,0,0};
 12 int diry[8]= {1,0,-1,1,0,-1,1,-1};
 13 int n,m,k;
 14 int num;
 15 using namespace std;
 16 bool juge(int x,int y)
 17 {
 18     if(x<0||x>=n||y<0||y>=m)
 19         return false;
 20     else
 21         return true;
 22 }
 23 void dfs(int x,int y)
 24 {
 25     vis[x][y]=true;
 26     int i;
 27     for(i=0; i<8; i++)
 28     {
 29         int xx=x+dirx[i];
 30         int yy=y+diry[i];
 31         if(juge(xx,yy))
 32         {
 33             if(map[xx][yy]==0&&vis[xx][yy]==false)
 34             {
 35                 dfs(xx,yy);
 36             }
 37             if(map[xx][yy]>0&&vis[xx][yy]==false)
 38             {
 39                 vis[xx][yy]=true;
 40                 num++;
 41             }
 42         }
 43     }
 44 }
 45 int main()
 46 {
 47     int T,K;
 48     while(scanf("%d",&T)!=EOF)
 49     {
 50         K=0;
 51         while(T--)
 52         {
 53             K++;
 54             scanf("%d%d%d",&n,&m,&k);
 55             int i,j;
 56             int x,y;
 57             memset(map,0,sizeof(map));
 58             memset(vis,0,sizeof(vis));
 59             for(i=0; i<k; i++)
 60             {
 61                 scanf("%d%d",&x,&y);
 62                 map[x][y]=-1;
 63                 for(j=0; j<8; j++)
 64                 {
 65                     int xx=x+dirx[j];
 66                     int yy=y+diry[j];
 67                     if(juge(xx,yy))
 68                     {
 69                         //printf("x=%d y=%d\n",xx,yy);
 70                         if(map[xx][yy]!=-1)
 71                         {
 72                             map[xx][yy]++;
 73                         }
 74                     }
 75                 }
 76             }
 77             /*for(i=0;i<n;i++)
 78             {
 79                 for(j=0;j<m;j++)
 80                 {
 81                     printf("%d ",map[i][j]);
 82                 }
 83                 printf("\n");
 84             }*/
 85             int num1=0,num2=0,nnum=0;
 86             for(i=0; i<n; i++)
 87             {
 88                 for(j=0; j<m; j++)
 89                 {
 90                     if(map[i][j]==0&&vis[i][j]==false)
 91                     {
 92                         num=0;
 93                         dfs(i,j);
 94                         if(num%2==0)
 95                             num2++;
 96                         else
 97                             num1++;
 98                     }
 99                 }
100             }
101             for(i=0; i<n; i++)
102             {
103                 for(j=0; j<m; j++)
104                 {
105                     if(map[i][j]>0&&vis[i][j]==false)
106                     {
107                         nnum++;
108                     }
109                 }
110             }
111             //printf("num1=%d num2=%d nnum=%d\n",num1,num2,nnum);
112             if(num1%2==1||(num2+nnum)%2==1)
113             {
114                 printf("Case #%d: Xiemao\n",K);
115             }
116             else
117             {
118                 printf("Case #%d: Fanglaoshi\n",K);
119             }
120         }
121     }
122 
123     return 0;
124 }
View Code

 

problem  1004  (hdu 4679)

Terrorist’s destroy

思路:(官方题解)

可以枚举删掉的边,通过记录一些值,dp 求出删掉此边后剩下两棵树的直径。

首先一遍dfs 求出以U 为根的子树直径f[U],以及子树中距离U 最长的点和U 的距离,和它是由U 的哪个儿子得到; 同时记录一个次大的,再记录一个次次大的。

然后第二遍dfs,求出除去以U 为根的子树后,剩下的子树的直径h[U]。

 

 

如上图:假设已经得到h[U] 了(h[ROOT] = 0),现在要求出除去以V为根的子树后,剩下树的直径h[V ],那么h[V ] 可能由四个方面得到:

1. 2 中h[U]。

2. 1 中U 的儿子的f 最大值。

3. 1 中从U 的儿子出发的一条最长的链+2 中从FA 出发的一条最长链+2(2 中从FA 出发的一条最长链,可以单独维护得到)。

4. 1 中从U 的儿子出发的一条最长的链+1 中从U 的儿子出发的一条次长链+2。

这样复杂度是O(n) 的。

代码好长,,好繁琐

  1 #include <iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<queue>
  6 #include<stack>
  7 #pragma comment(linker, "/STACK:1024000000,1024000000")
  8 using namespace std;
  9 const int maxn=100010;
 10 struct node
 11 {
 12     int u;
 13     int v;
 14     int w;
 15     int next;
 16     int res;
 17 } edge[maxn*2];
 18 struct nnode
 19 {
 20     int m1,x1;//最长路:长度和儿子
 21     int m2,x2;//次长路
 22     int m3,x3;//次次长路
 23     int f1,fx1;//最长链及其儿子
 24     int f2,fx2;//次长链及其儿子
 25     int len;//最长链
 26     int h;//切断后最长链
 27     int pre;//祖先最长路
 28 } st[maxn];
 29 int lenth[maxn*2];
 30 int cnt;
 31 int head[maxn];
 32 bool vis[maxn];
 33 int n;
 34 void init()
 35 {
 36     cnt=0;
 37     memset(head,-1,sizeof(head));
 38     memset(vis,0,sizeof(vis));
 39     int i;
 40     for(i=0; i<=n; i++)
 41     {
 42         st[i].m1=st[i].m2=st[i].m3=st[i].x1=st[i].x2=st[i].x3=st[i].len=0;
 43         st[i].f1=st[i].fx1=0;
 44         st[i].f2=st[i].fx2=0;
 45         st[i].pre=0;
 46         st[i].h=0;
 47     }
 48 }
 49 void add(int u,int v,int w)
 50 {
 51     edge[cnt].u=u;
 52     edge[cnt].v=v;
 53     edge[cnt].w=w;
 54     edge[cnt].res=0;
 55     edge[cnt].next=head[u];
 56     head[u]=cnt++;
 57 
 58 }
 59 void dfs(int s)
 60 {
 61     int i;
 62     vis[s]=1;
 63     if(head[s]==-1)
 64     {
 65         st[s].m1=st[s].m2=st[s].m3=1;
 66         st[s].x1=st[s].x2=st[s].x3=-1;
 67         st[s].f1=st[s].fx1=0;
 68         st[s].f2=st[s].fx2=0;
 69         st[s].len=0;
 70         return ;
 71     }
 72     for(i=head[s]; i!=-1; i=edge[i].next)
 73     {
 74         int v=edge[i].v;
 75         if(!vis[v])
 76         {
 77             dfs(v);
 78             if(st[v].m1>st[s].m1)
 79             {
 80                 st[s].m3=st[s].m2;
 81                 st[s].m2=st[s].m1;
 82                 st[s].m1=st[v].m1;
 83                 st[s].x3=st[s].x2;
 84                 st[s].x2=st[s].x1;
 85                 st[s].x1=v;
 86             }
 87             else
 88             {
 89                 if(st[v].m1>st[s].m2)
 90                 {
 91                     st[s].m3=st[s].m2;
 92                     st[s].m2=st[v].m1;
 93                     st[s].x3=st[s].x2;
 94                     st[s].x2=v;
 95                 }
 96                 else
 97                 {
 98                     if(st[v].m1>st[s].m3)
 99                     {
100                         st[s].m3=st[v].m1;
101                         st[s].x3=v;
102                     }
103                 }
104             }
105             if(st[v].len>st[s].f1)
106             {
107                 st[s].f2=st[s].f1;
108                 st[s].f1=st[v].len;
109                 st[s].fx2=st[s].fx1;
110                 st[s].fx1=v;
111             }
112             else if(st[v].len>st[s].f2)
113             {
114                 st[s].f2=st[v].len;
115                 st[s].fx2=v;
116             }
117             st[s].len=max(st[s].len,st[v].len);
118         }
119     }
120     st[s].m1++;
121     if(st[s].m3!=0)
122         st[s].m3++;
123     if(st[s].m2!=0)
124     {
125         st[s].m2++;
126         st[s].len=max(st[s].len,st[s].m1+st[s].m2-2);
127     }
128     else
129     {
130         st[s].len=max(st[s].len,st[s].m1-1);
131     }
132 }
133 void dfs1(int ss,int s)
134 {
135     vis[s]=true;
136     int i;
137     if(head[s]==-1)
138         return ;
139     for(i=head[s]; i!=-1; i=edge[i].next)
140     {
141 
142         int v=edge[i].v;
143 
144         if(vis[v])
145             continue;
146         //printf("u=%d   v=%d\n",s,v);
147         /*
148         包含父节点的祖先最长一条路
149         */
150         if(st[ss].x1!=s)
151             st[s].pre=st[ss].m1;
152         else
153             st[s].pre=st[ss].m2;
154         if(s!=1)
155         {
156             st[s].pre=max(st[s].pre,st[ss].pre+1);
157         }
158 
159         //printf("pre=%d\n",st[s].pre);
160 
161         //1.除去父节点子树(包括父节点)后的最长链
162         st[v].h=st[s].h;
163         //printf("h[u]=%d\n",st[v].h);
164         //2.其他兄弟的最长链
165         if(st[s].fx1==v)
166         {
167             st[v].h=max(st[v].h,st[s].f2);
168            // printf("其他兄弟最长=%d\n",st[s].f2);
169         }
170 
171         else
172         {
173             st[v].h=max(st[v].h,st[s].f1);
174             //printf("其他兄弟最长=%d\n",st[s].f1);
175         }
176 
177 
178         //3.其他两个兄弟的最长路之和
179         int u;
180         if(v==st[s].x1)
181         {
182             if(st[s].m2!=0)
183             {
184                 st[v].h=max(st[v].h,st[ss].pre+st[s].m2-1);//4.祖先的最长路+父亲+其他兄弟的最长路;
185                 //printf("pre=%d  m2=%d  \n",st[ss].pre,st[s].m2);
186                 //printf("1.兄弟+祖先=%d\n",st[ss].pre+st[s].m2-1);
187                 if(st[s].m3!=0)
188                 {
189                     u=st[s].m2+st[s].m3-2;
190                 }
191                 else
192                 {
193                     u=st[s].m2-1;
194                 }
195             }
196             else
197             {
198                 st[v].h=max(st[v].h,st[ss].pre);//4.祖先的最长路+父亲+其他兄弟的最长路;
199                 //printf("2.兄弟+祖先=%d\n",st[ss].pre);
200                 u=0;
201             }
202             st[v].h=max(st[v].h,u);
203             //printf("其他俩兄弟长度之和=%d\n",u);
204         }
205         else
206         {
207             //printf("pre=%d m1=%d ",st[s].pre,st[s].m1);
208             st[v].h=max(st[v].h,st[ss].pre+st[s].m1-1);//4.祖先的最长路+父亲+其他兄弟的最长路;
209             //printf("3.兄弟+祖先=%d\n",st[ss].pre+st[s].m1-1);
210             if(v==st[s].x2)
211             {
212                 if(st[s].m3==0)
213                 {
214                     u=st[s].m1-1;
215                 }
216                 else
217                 {
218                     u=st[s].m1+st[s].m3-2;
219                 }
220                 st[v].h=max(st[v].h,u);
221                // printf("其他俩兄弟长度之和=%d\n",u);
222             }
223             else
224             {
225                 u=st[s].m1+st[s].m2-2;
226                 st[v].h=max(st[v].h,u);
227             }
228         }
229         //printf("u=%d v=%d  h=%d len=%d\n\n\n\n",s,v,st[v].h,st[v].len);
230 
231         edge[i].res=max(st[v].h,st[v].len);
232         //printf("i=%d  res=%d\n",i,edge[i].res);
233         if(v==st[s].x1)
234         {
235             if(st[s].m2!=0)
236                 st[s].pre=max(st[s].pre,st[s].m2);
237         }
238         else
239         {
240             st[s].pre=max(st[s].pre,st[s].m1);
241         }
242         dfs1(s,v);
243     }
244 }
245 int main()
246 {
247     int T,K=0;
248     scanf("%d",&T);
249     while(T--)
250     {
251         K++;
252         int u,v,w;
253         init();
254         int i;
255         scanf("%d",&n);
256         for(i=0; i<n-1; i++)
257         {
258             scanf("%d%d%d",&u,&v,&w);
259             add(u,v,w);
260             add(v,u,w);
261         }
262         /*printf("cnt=%d\n",cnt);
263         for(i=0;i<cnt;i++)
264         {
265             printf("%d %d %d\n",edge[i].u,edge[i].v,edge[i].w);
266         }*/
267         dfs(1);
268         /*for(i=1; i<=n; i++)
269         {
270             printf("i=%d :   x1=%d m1=%d   x2=%d m2=%d   x3=%d m3=%d     len=%d\n",i,st[i].x1,st[i].m1,st[i].x2,st[i].m2,st[i].x3,st[i].m3,st[i].len);
271         }
272         printf("jif\n\n");*/
273         memset(vis,0,sizeof(vis));
274         dfs1(0,1);
275         int ans=1e9+1000;
276         int pos;
277         for(i=0; i<cnt; i++)
278         {
279             //printf("%d=%d ",i/2,edge[i].res);
280             if(edge[i].res>0&&edge[i].res*edge[i].w<ans)
281             {
282                 ans=edge[i].res*edge[i].w;
283                 pos=i/2;
284             }
285         }
286         printf("Case #%d: %d\n",K,pos+1);
287     }
288     return 0;
289 }
View Code

 

problem 1006(hdu 4681)

String

思路:(官方题解)

首先枚举C 在A 和B 的起始位置,要使A 和B 的公共子序列尽量大,那么C 在A 和B 的占用长度肯定越少越好。所以就分成两个问题:

1. 对A,B 的任意起始位置,求出最近的包含C 的结束位置。先记录一个数组A[i][j](0  i < lenA; 0  j < 26) 保存在i 位置后跟 i 最近的字符j 的距离。这个数组可以O(N2) 暴力枚举出来然后对于每个起始位置i,按C从左往右寻找距离当前位置最近的相应字符即可。

2. 对于任意A,B 的起始位置,求出A,B 在起始位置之前的最长公共子序列,用同样的方法求出与起始位置相应的结束位置以后的最长公共子序列。只需定义dp[i][j] 代表A 的i 位置下B 的j 位置下的最长公共子序列长度。复杂度为O(lenA  lenB)。

上面两个问题都预处理后每次查询为O(1)。所以总复杂度为O(N2).

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=1010;
  7 int dp1[maxn][maxn];
  8 int dp2[maxn][maxn];
  9 char stra[maxn];
 10 char strb[maxn];
 11 char strc[maxn];
 12 int st1[maxn][2];
 13 int st2[maxn][2];
 14 int main()
 15 {
 16     //freopen("in.txt","r",stdin);
 17     //freopen("out.out","w",stdout);
 18     int T,K=0;
 19     scanf("%d",&T);
 20     getchar();
 21     while(T--)
 22     {
 23         memset(dp1,0,sizeof(dp1));
 24         memset(dp2,0,sizeof(dp2));
 25         memset(st1,0,sizeof(st1));
 26         memset(st2,0,sizeof(st2));
 27         gets(stra);
 28         gets(strb);
 29         gets(strc);
 30         K++;
 31         int lena=strlen(stra);
 32         int lenb=strlen(strb);
 33         int lenc=strlen(strc);
 34         int i;
 35         int j;
 36 
 37         for(i=0; i<=lena; i++)
 38         {
 39             dp1[i][0]=0;
 40         }
 41         for(j=0; j<=lenb; j++)
 42         {
 43             dp1[0][j]=0;
 44         }
 45         for(i=1; i<=lena; i++)
 46         {
 47             for(j=1; j<=lenb; j++)
 48             {
 49                 if(stra[i-1]==strb[j-1])
 50                     dp1[i][j]=dp1[i-1][j-1]+1;
 51                 else
 52                     dp1[i][j]=max(dp1[i][j-1],dp1[i-1][j]);
 53             }
 54         }
 55         for(i=0; i<=lena; i++)
 56         {
 57             dp2[i][lena]=0;
 58         }
 59         for(j=0; j<=lenb; j++)
 60         {
 61             dp2[lenb][j]=0;
 62         }
 63         for(i=lena-1; i>=0; i--)
 64         {
 65             for(j=lenb-1; j>=0; j--)
 66             {
 67                 if(stra[i]==strb[j])
 68                     dp2[i][j]=dp2[i+1][j+1]+1;
 69                 else
 70                     dp2[i][j]=max(dp2[i+1][j],dp2[i][j+1]);
 71             }
 72         }
 73         /*for(i=0;i<=lena;i++)
 74         {
 75             for(j=0;j<=lenb;j++)
 76             {
 77                 printf("%d ",dp1[i][j]);
 78             }
 79             printf("\n");
 80         }
 81         for(i=lena;i>=0;i--)
 82         {
 83             for(j=lenb;j>=0;j--)
 84             {
 85                 printf("%d ",dp2[i][j]);
 86             }
 87             printf("\n");
 88         }*/
 89         int mmax=0;
 90         int k;
 91         int ii,jj,kk;
 92         int u=0;
 93         for(i=0; i<lena; i++)
 94         {
 95             if(stra[i]==strc[0])
 96             {
 97                 for(j=i,k=0; k<lenc&&j<lena;)
 98                 {
 99                     if(stra[j]==strc[k])
100                         k++,j++;
101                     else
102                         j++;
103                 }
104                 if(k!=lenc)
105                     continue;
106                 st1[u][0]=i;
107                 st1[u][1]=j;
108                 u++;
109             }
110         }
111         int uu=0;
112         for(ii=0; ii<lena; ii++)
113         {
114             if(strb[ii]==strc[0])
115             {
116                 for(jj=ii,kk=0; kk<lenc&&jj<lenb;)
117                 {
118                     if(strb[jj]==strc[kk])
119                         kk++,jj++;
120                     else
121                         jj++;
122                 }
123                 if(kk!=lenc)
124                     continue;
125                 st2[uu][0]=ii;
126                 st2[uu][1]=jj;
127                 uu++;
128             }
129         }
130         int num;
131         for(i=0; i<u; i++)
132         {
133             for(j=0; j<uu; j++)
134             {
135                 num=dp1[st1[i][0]][st2[j][0]]+dp2[st1[i][1]][st2[j][1]]+lenc;
136                 if(mmax<num)
137                     mmax=num;
138             }
139         }
140         //num=dp1[i][ii]+dp2[j][jj]+lenc;
141         //printf(" [%d]     [%d]\n",dp1[i][ii],dp2[j][jj]);
142         printf("Case #%d: %d\n",K,mmax);
143 
144     }
145     return 0;
146 }
View Code

 

posted @ 2013-08-18 22:10  琳&leen  阅读(259)  评论(0编辑  收藏  举报