最近几天一直在做DP,又学习了两种方法:斜率优化,单调队列优化。
hdu 2577 How to Type
http://acm.hdu.edu.cn/showproblem.php?pid=2577
打印字母,很经典的一类dp,用二维数组表示:
dp[i][0]表示打印完第i个字符,键盘上的大写锁定键是关闭着的。
dp[i][1]表示打印完第i个字符,键盘上的大写锁定键的打开着的。
那么根据第i个字母的大小写就很容易写出前后的转化关系。
code:
1 # include<stdio.h>
2 # include<string.h>
3 int min(int a,int b)
4 {
5 return a<b?a:b;
6 }
7 int main()
8 {
9 int i,dp[105][2],ncase;
10 char str[105];
11 scanf("%d",&ncase);
12 while(ncase--)
13 {
14 scanf("%s",str+1);
15 memset(dp,0,sizeof(dp));
16 dp[0][0]=0;
17 dp[0][1]=1;
18 for(i=1;str[i];i++)
19 {
20 if(str[i]>='a' && str[i]<='z')
21 {
22 dp[i][0]=min(dp[i-1][0]+1,dp[i-1][1]+2);
23 dp[i][1]=min(dp[i-1][1]+2,dp[i-1][0]+2);
24 }
25 else
26 {
27 dp[i][0]=min(dp[i-1][0]+2,dp[i-1][1]+2);
28 dp[i][1]=min(dp[i-1][0]+2,dp[i-1][1]+1);
29 }
30 }
31 printf("%d\n",min(dp[i-1][0],dp[i-1][1]+1));
32 }
33 return 0;
34 }
hdu 1513 Palindrome
http://acm.hdu.edu.cn/showproblem.php?pid=1513
求把一个字符串转化成回文需要最少的操作次数。
把这个字符串反过来写一遍,然后这两个字符串求最长公共子序列。
最后字符串长度-公共子序列长度就是最少的操作数。
长度比较大, 需要用到滚动数组。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 5005
4 int max(int a,int b)
5 {
6 return a>b?a:b;
7 }
8 int main()
9 {
10 int i,j,n,dp[2][N];
11 char str1[N],str2[N];
12 while(scanf("%d",&n)!=EOF)
13 {
14 scanf("%s",str1+1);
15 for(i=n;i>=1;i--)
16 str2[i]=str1[n-i+1];
17 memset(dp,0,sizeof(dp));
18 for(i=1;i<=n;i++)
19 for(j=1;j<=n;j++)
20 {
21 if(str1[i]==str2[j])
22 dp[i%2][j]=dp[(i-1)%2][j-1]+1;
23 else dp[i%2][j]=max(dp[(i-1)%2][j],dp[i%2][j-1]);
24 }
25 printf("%d\n",n-dp[n%2][n]);
26 }
27 return 0;
28 }
hdu 3351 Seinfeld
http://acm.hdu.edu.cn/showproblem.php?pid=3351
字符串匹配问题,此题比较简单。
在读入的过程中,把相匹配的删除,最后会存在下面三种形态:
1. }}}...
2. {{{...
3. }}}...{{{...
对于每种形态就很容易求了。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 2005
4 int main()
5 {
6 int i,n,ncase=0,a,b,ans,top;
7 char str[N],map[N];
8 while(scanf("%s",str+1)!=EOF)
9 {
10 ncase++;
11 if(str[1]=='-') break;
12 n=strlen(str);
13 top=0;
14 for(i=1;i<n;i++)
15 {
16 if(top==0)
17 {
18 top++;
19 map[top]=str[i];
20 }
21 else
22 {
23 if(str[i]=='}' && map[top]=='{') top--;
24 else map[++top]=str[i];
25 }
26 }
27 ans=0;
28 if(top==0 || map[top]=='}') ans=top/2;
29 else
30 {
31 if(map[1]=='{') ans=top/2;
32 else
33 {
34 for(i=1;i<=top;i++)
35 if(map[i]!='}') break;
36 a=i-1;
37 b=top-a;
38 ans=(a+1)/2+(b+1)/2;
39 }
40 }
41 printf("%d. %d\n",ncase,ans);
42 }
43 return 0;
44 }
hdu 1978 How many ways
http://acm.hdu.edu.cn/showproblem.php?pid=1978
简单DP,从左到右,从上到下依次访问每一个位置。
从该位置(x0,y0)能到达的所有位置(xi,yi),
dp[xi][yi]+=dp[x0][y0];
1 # include<stdio.h>
2 # include<string.h>
3 # define N 105
4 int map[N][N],dp[N][N];
5 int main()
6 {
7 int i,j,n,m,ncase,i1,j1;
8 scanf("%d",&ncase);
9 while(ncase--)
10 {
11 scanf("%d%d",&n,&m);
12 for(i=1;i<=n;i++)
13 for(j=1;j<=m;j++)
14 scanf("%d",&map[i][j]);
15 memset(dp,0,sizeof(dp));
16 dp[1][1]=1;
17 for(i=1;i<=n;i++)
18 for(j=1;j<=m;j++)
19 {
20 for(i1=i; i1-i<=map[i][j]&&i1<=n;i1++)
21 {
22 for(j1=j;j1-j+i1-i<=map[i][j]&&j1<=m;j1++)
23 {
24 if(i1==i &&j1==j) continue;
25 dp[i1][j1]+=dp[i][j];
26 dp[i1][j1]%=10000;
27 }
28 }
29 }
30 printf("%d\n",dp[n][m]);
31 }
32 return 0;
33 }
hdu 1506 Largest Rectangle in a Histogram
http://acm.hdu.edu.cn/showproblem.php?pid=1506
求能够成的最大矩形的面积。
遍历每个点,向两边延展,遇到比该点低的停止。
求出宽度,宽度*该点的高度就是在该点时的最大面积。
需要用两个数组记录,否则会超时。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 100005
4 int l[N],r[N];
5 __int64 a[N],Max;
6 __int64 max(__int64 a,__int64 b)
7 {
8 return a>b?a:b;
9 }
10 int main()
11 {
12 int i,n;
13 while(scanf("%d",&n)!=EOF && n)
14 {
15 for(i=1;i<=n;i++)
16 {
17 scanf("%I64d",&a[i]);
18 l[i]=r[i]=i;
19 }
20 Max=0;
21 a[n+1]=a[0]=-1;
22 for(i=1;i<=n;i++)
23 {
24 while(a[l[i]-1]>=a[i])
25 l[i]=l[l[i]-1];
26 }
27 for(i=n;i>=1;i--)
28 {
29 while(a[r[i]+1]>=a[i])
30 r[i]=r[r[i]+1];
31 }
32 for(i=1;i<=n;i++)
33 {
34 Max=max((r[i]-l[i]+1)*a[i],Max);
35 }
36 printf("%I64d\n",Max);
37 }
38 return 0;
39 }
hdu 1505 City Game
http://acm.hdu.edu.cn/showproblem.php?pid=1505
上题的加强版,加一个数组记录就可以了。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 1005
4 int map[N][N],dp[N][N],s[N],Max,l[N],r[N];
5 int max(int a,int b)
6 {
7 return a>b?a:b;
8 }
9 int main()
10 {
11 int i,j,n,m,ncase;
12 char ch[3];
13 scanf("%d",&ncase);
14 while(ncase--)
15 {
16 scanf("%d%d",&n,&m);
17 memset(dp,0,sizeof(dp));
18 for(i=1;i<=n;i++)
19 {
20 for(j=1;j<=m;j++)
21 {
22 scanf("%s",ch);
23 if(ch[0]=='R') map[i][j]=0;
24 else map[i][j]=1;
25 }
26 }
27 Max=0;
28 for(i=1;i<=n;i++)
29 {
30 for(j=1;j<=m;j++)
31 {
32 if(map[i][j]) dp[i][j]=dp[i-1][j]+1;
33 s[j]=dp[i][j];
34 l[j]=r[j]=j;
35 }
36 s[0]=-1;
37 s[m+1]=-1;
38 for(j=1;j<=n;j++)
39 {
40 while(s[l[j]-1]>=s[j])
41 l[j]=l[l[j]-1];
42 }
43 for(j=n;j>=1;j--)
44 {
45 while(s[r[j]+1]>=s[j])
46 r[j]=r[r[j]+1];
47 }
48 for(j=1;j<=n;j++)
49 Max=max(Max,(r[j]-l[j]+1)*s[j]);
50 }
51 printf("%d\n",Max*3);
52 }
53 return 0;
54 }
hdu 2870 Largest Submatrix
http://acm.hdu.edu.cn/showproblem.php?pid=2870
上题 的加强版。
三种情况。
全部变为a,全部为b,全部为c,分别求最大。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 1005
4 char map[N][N];
5 int dp[N][N][3],Max,s[N],l[N],r[N];
6 int max(int a,int b)
7 {
8 return a>b?a:b;
9 }
10 int is1(char ch)
11 {
12 if(ch=='a'||ch=='w'||ch=='y'||ch=='z') return 1;
13 return 0;
14 }
15 int is2(char ch)
16 {
17 if(ch=='b'||ch=='w'||ch=='x'||ch=='z') return 1;
18 return 0;
19 }
20 int is3(char ch)
21 {
22 if(ch=='c'||ch=='x'||ch=='y'||ch=='z') return 1;
23 return 0;
24 }
25 int main()
26 {
27 int i,j,n,m;
28 while(scanf("%d%d",&n,&m)!=EOF)
29 {
30 for(i=1;i<=n;i++)
31 {
32 scanf("%s",map[i]);
33 for(j=m-1;j>=0;j--)
34 map[i][j+1]=map[i][j];
35 }
36 memset(dp,0,sizeof(dp));
37 Max=0;
38 for(i=1;i<=n;i++)
39 {
40 for(j=1;j<=m;j++)
41 {
42 if(is1(map[i][j])) dp[i][j][0]=dp[i-1][j][0]+1;
43 if(is2(map[i][j])) dp[i][j][1]=dp[i-1][j][1]+1;
44 if(is3(map[i][j])) dp[i][j][2]=dp[i-1][j][2]+1;
45 }
46 for(j=1;j<=m;j++)
47 {
48 s[j]=dp[i][j][0];
49 l[j]=r[j]=j;
50 }
51 s[0]=s[m+1]=-1;
52 for(j=1;j<=m;j++)
53 {
54 while(s[l[j]-1]>=s[j])
55 l[j]=l[l[j]-1];
56 }
57 for(j=m;j>=1;j--)
58 {
59 while(s[r[j]+1]>=s[j])
60 r[j]=r[r[j]+1];
61 }
62 for(j=1;j<=m;j++)
63 Max=max(Max,(r[j]-l[j]+1)*s[j]);
64
65 for(j=1;j<=m;j++)
66 {
67 s[j]=dp[i][j][1];
68 l[j]=r[j]=j;
69 }
70 s[0]=s[m+1]=-1;
71 for(j=1;j<=m;j++)
72 {
73 while(s[l[j]-1]>=s[j])
74 l[j]=l[l[j]-1];
75 }
76 for(j=m;j>=1;j--)
77 {
78 while(s[r[j]+1]>=s[j])
79 r[j]=r[r[j]+1];
80 }
81 for(j=1;j<=m;j++)
82 Max=max(Max,(r[j]-l[j]+1)*s[j]);
83 for(j=1;j<=m;j++)
84 {
85 s[j]=dp[i][j][2];
86 l[j]=r[j]=j;
87 }
88 s[0]=s[m+1]=-1;
89 for(j=1;j<=m;j++)
90 {
91 while(s[l[j]-1]>=s[j])
92 l[j]=l[l[j]-1];
93 }
94 for(j=m;j>=1;j--)
95 {
96 while(s[r[j]+1]>=s[j])
97 r[j]=r[r[j]+1];
98 }
99 for(j=1;j<=m;j++)
100 Max=max(Max,(r[j]-l[j]+1)*s[j]);
101 }
102 printf("%d\n",Max);
103 }
104 return 0;
105 }
hdu 2686 Matrix
http://acm.hdu.edu.cn/showproblem.php?pid=2686
多线程DP。
题意:从左上角走到右下角,再从右下角走到左上角,保证所走得两条路线不相交,问最后能得到的最少数(每走到一个点上就加上该点的值)
思路:可以转化为同时从左上角出发的两条线。
枚举步数:dp(k,x1,y1,x2,y2)=max[dp(k-1,x1-1,y1,x2-1,y2),dp(k-1,x1-1,y1,x2,y2-1),dp(k-1,x1,y1-1,x2-1,y2),dp(k-1,x1,y1-1,x2,y2-1)];
需保证x1!=x2&&y1!=y2;
因为坐标(x1,y1)与步数k之间有一个关系,只要知道k与x1就能求出y1,所以可以转化为一个三维的。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 31
4 int dp[2*N][N][N],a[3],b[3],map[N][N];
5 int max(int a,int b)
6 {
7 return a>b?a:b;
8 }
9 int main()
10 {
11 int i,j,n,x1,x2,i1,i2,k;
12 while(scanf("%d",&n)!=EOF)
13 {
14 for(i=0;i<n;i++)
15 for(j=0;j<n;j++)
16 scanf("%d",&map[i][j]);
17 memset(dp,0,sizeof(dp));
18 for(k=1;k<=2*n-3;k++)
19 {
20 for(x1=0;x1<=k;x1++)
21 {
22 for(x2=x1+1;x2<=k;x2++)
23 {
24 a[1]=x1;
25 a[2]=x1-1;
26 b[1]=x2;
27 b[2]=x2-1;
28 for(i1=1;i1<=2;i1++)
29 for(i2=1;i2<=2;i2++)
30 {
31 if(a[i1]==b[i2]) continue;
32 dp[k][x1][x2]=max(dp[k][x1][x2],dp[k-1][a[i1]][b[i2]]);
33 }
34 dp[k][x1][x2]+=map[x1][k-x1]+map[x2][k-x2];
35 }
36 }
37 }
38 dp[2*n-2][n-1][n-1]=max(dp[2*n-3][n-1][n-2],dp[2*n-3][n-2][n-1])+map[n-1][n-1];
39 printf("%d\n",dp[2*n-2][n-1][n-1]+map[0][0]);
40 }
41 return 0;
42 }
hdu 3392 Pie
http://acm.hdu.edu.cn/showproblem.php?pid=3392
输入n个男生,m个女生的身高。
把人数较少的一方和另外一方匹配完,求最少的差值。
分别把男女的身高排序。人数较少的一方的每个人可以匹配abs(m-n+1)个人。
因为|m-n|<=100 所以一个人最多匹配100人。
之后用二维滚动数组就可以了。
1 # include<stdio.h>
2 # include<stdlib.h>
3 # include<math.h>
4 # include<string.h>
5 # define N 10005
6 double dp[2][105];
7 int cmp(const void *a,const void *b)
8 {
9 return *(double *)a > *(double *)b ? 1 : -1;
10 }
11 double min(double a,double b)
12 {
13 return a<b?a:b;
14 }
15 int main()
16 {
17 int i,j,n,m,tmp,k,len;
18 double a[N],b[N];
19 while(scanf("%d%d",&n,&m)!=EOF)
20 {
21 if(n==0 && m==0) break;
22 if(n<=m)
23 {
24 for(i=1;i<=n;i++)
25 scanf("%lf",&a[i]);
26 for(i=1;i<=m;i++)
27 scanf("%lf",&b[i]);
28 }
29 else
30 {
31 for(i=1;i<=n;i++)
32 scanf("%lf",&b[i]);
33 for(i=1;i<=m;i++)
34 scanf("%lf",&a[i]);
35 tmp=n;
36 n=m;
37 m=tmp;
38 }
39 qsort(a+1,n,sizeof(a[1]),cmp);
40 qsort(b+1,m,sizeof(b[1]),cmp);
41 len=m-n+1;
42 for(i=0;i<2;i++)
43 for(j=0;j<=len;j++)
44 dp[i][j]=0;
45 for(i=1;i<=n;i++)
46 {
47 dp[i%2][1]=dp[(i-1)%2][1]+fabs(a[i]-b[i]);
48 for(k=2;k<=len;k++)
49 {
50 j=k+i-1;
51 dp[i%2][k]=min(dp[(i-1)%2][k]+fabs(a[i]-b[j]),dp[i%2][k-1]);
52 }
53 }
54 printf("%.6lf\n",dp[n%2][len]);
55 }
56 return 0;
57 }
hdu 1422 重温世界杯
http://acm.hdu.edu.cn/showproblem.php?pid=1422
因为可以构成一个环,所以可以把前面的n-1复制到后面
s[n+1]=s[1];s[n+2]=s[2]......
之后就很简单了,在保证sum>=0的情况下求最多能访问多少个城市。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 100005
4 int s[2*N];
5 int max(int a,int b)
6 {
7 return a>b?a:b;
8 }
9 int main()
10 {
11 int i,j,n,end,count,Max,a,b;
12 while(scanf("%d",&n)!=EOF)
13 {
14 for(i=1;i<=n;i++)
15 {
16 scanf("%d%d",&a,&b);
17 s[i]=a-b;
18 }
19 for(i=n+1;i<=2*n-1;i++)
20 s[i]=s[i-n];
21 end=0;
22 count=0;
23 Max=0;
24 for(i=1;i<=2*n-1;i++)
25 {
26 if(end+s[i]>=0) {count++;end+=s[i];}
27 else
28 {
29 Max=max(Max,count);
30 if(Max>=n) break;
31 count=0;
32 end=0;
33 }
34 }
35 Max=max(Max,count);
36 if(Max>=n) Max=n;
37 printf("%d\n",Max);
38 }
39 return 0;
40 }
hdu 2830 Matrix Swapping II
http://acm.hdu.edu.cn/showproblem.php?pid=2830
也是求最大矩阵的,只不过可以相互交换任意两列。
访问每一行时,求出每个点的高度,然后排序,以该点为高时的宽度就很容易看出来,面积取最大的就可以了。
1 # include<stdio.h>
2 # include<string.h>
3 # include<stdlib.h>
4 # define N 1005
5 char map[N][N];
6 int dp[N][N],s[N];
7 int cmp(const void *a,const void *b)
8 {
9 return *(int *)a - *(int *)b;
10 }
11 int max(int a,int b)
12 {
13 return a>b?a:b;
14 }
15 int main()
16 {
17 int i,j,n,m,k,Max;
18 while(scanf("%d%d",&n,&m)!=EOF)
19 {
20 for(i=1;i<=n;i++)
21 {
22 scanf("%s",&map[i]);
23 for(j=m-1;j>=0;j--)
24 map[i][j+1]=map[i][j];
25 }
26 memset(dp,0,sizeof(dp));
27 Max=0;
28 for(i=1;i<=n;i++)
29 {
30 k=0;
31 for(j=1;j<=m;j++)
32 {
33 if(map[i][j]=='1')
34 {
35 dp[i][j]=dp[i-1][j]+1;
36 s[++k]=dp[i][j];
37 }
38 }
39 qsort(s+1,k,sizeof(s[1]),cmp);
40 for(j=1;j<=k;j++)
41 Max=max(Max,s[j]*(k-j+1));
42 }
43 printf("%d\n",Max);
44 }
45 return 0;
46 }
hdu 3415 Max Sum of Max-K-sub-sequence
http://acm.hdu.edu.cn/showproblem.php?pid=3415
最大的序列和,不过这个序列的长度不能超过k.
在i点时的最大和为sum[i]-min(sum[j]); i-k<=j<=i
枚举会超时,这里就用到了单调队列。
/*
单调队列即保持队列中的元素单调递增(或递减)的这样一个队列,可以从两头删除,只能从队尾插入。
单调队列的具体作用在于,由于保持队列中的元素满足单调性,对于上述问题中的每个j,可以用O(1)的时间找到对应的s[i]。
(保持队列中的元素单调增的话,队首元素便是所要的元素了)。
维护方法:对于每个j,我们插入s[j-1](为什么不是s[j]? 队列里面维护的是区间开始的下标,j是区间结束的下标),插入时从队尾插入。
为了保证队列的单调性,我们从队尾开始删除元素,直到队尾元素比当前需要插入的元素优
(本题中是值比待插入元素小,位置比待插入元素靠前,不过后面这一个条件可以不考虑),就将当前元素插入到队尾。
之所以可以将之前的队列尾部元素全部删除,是因为它们已经不可能成为最优的元素了,因为当前要插入的元素位置比它们靠前,值比它们小。
我们要找的,是满足(i>=j-k+1)的i中最小的s[i],位置越大越可能成为后面的j的最优s[i]。
*/
1 # include<stdio.h>
2 # include<string.h>
3 # define N 100005
4 int a[2*N],sum[2*N],s[2*N];
5 int main()
6 {
7 int i,ncase,n,k,from,to,top,end,Max,m;
8 scanf("%d",&ncase);
9 while(ncase--)
10 {
11 scanf("%d%d",&n,&k);
12 sum[0]=0;
13 for(i=1;i<=n;i++)
14 {
15 scanf("%d",&a[i]);
16 sum[i]=sum[i-1]+a[i];
17 }
18 for(i=n+1;i<=n+k-1;i++)
19 sum[i]=sum[i-1]+a[i-n];
20 top=1;
21 end=1;
22 m=n;
23 n=n+k-1;
24 s[1]=0;
25 Max=(k+1)*(-1000);
26 for(i=1;i<=n;i++)
27 {
28 while(end-top>=0 && sum[s[end]]>sum[i-1])
29 end--;
30 while(end-top>=0 && i-s[top]>k)
31 top++;
32 s[++end]=i-1;
33 if(sum[i]-sum[s[top]]>Max)
34 {
35 Max=sum[i]-sum[s[top]];
36 from=s[top]+1;
37 to=i;
38 }
39 }
40 printf("%d %d %d\n",Max,from,(to-1)%m+1);
41 }
42 return 0;
43 }
hdu 2993 MAX Average Problem
http://acm.hdu.edu.cn/showproblem.php?pid=2993
看见此题就用dp开始乱搞,最后跑了700ms+wa了。。
这里要用到斜率优化,给大家推荐一篇不错的论文:
http://www.docin.com/p-47950655.html
1 # include<stdio.h>
2 # include<string.h>
3 # define N 100005
4 double sum[N];
5 int top,s[N];
6 double K(int i,int j,int k)
7 {
8 double tmp;
9 tmp=(k-i)*(sum[j]-sum[i])-(j-i)*(sum[k]-sum[i]);
10 return tmp;
11 }
12 double max(double a,double b)
13 {
14 return a>b?a:b;
15 }
16 int readT()
17 {
18 char c;
19 int ret;
20 while(c=getchar(),c<'0'||c>'9');
21 ret = c - '0';
22 while(c=getchar(),c>='0'&&c<='9') ret = ret * 10 + c-'0';
23 return ret;
24 }
25 double asc(int i,int k)
26 {
27 i=s[i];
28 return (sum[k]-sum[i])/(k-i);
29 }
30 int main()
31 {
32 int i,j,n,k,f;
33 double Max;
34 while(scanf("%d%d",&n,&k)!=EOF)
35 {
36 sum[0]=0;
37 for(i=1;i<=n;i++)
38 sum[i]=sum[i-1]+readT();
39 top=0;
40 f=0;
41 Max=0;
42 for(i=k;i<=n;i++)
43 {
44 j=i-k;
45 while(top-f>=1 && K(s[top-1],s[top],j)>=0) top--;
46 s[++top]=j;
47 while(top-f>=1 && asc(f+1,i)>=asc(f,i))
48 f++;
49 Max=max(Max,asc(f,i));
50 }
51 printf("%.2lf\n",Max);
52 }
53 return 0;
54 }
hdu 1950 Bridging signals
http://acm.hdu.edu.cn/showproblem.php?pid=1950
转化为求最长上升子序列。
数据比较大,用二分法。
1 # include<stdio.h>
2 # include<string.h>
3 # define N 40005
4 int top,s[N],a[N];
5 int find(int x)
6 {
7 int left,mid,right,ans;
8 left=1;
9 right=top;
10 if(x>s[top]) return ++top;
11 while(right>=left)
12 {
13 mid=(left+right)/2;
14 if(s[mid]==x) return mid;
15 if(s[mid]>x) {ans=mid;right=mid-1;}
16 else left=mid+1;
17 }
18 return ans;
19 }
20 int main()
21 {
22 int i,n,ncase,ans;
23 scanf("%d",&ncase);
24 while(ncase--)
25 {
26 scanf("%d",&n);
27 for(i=1;i<=n;i++)
28 scanf("%d",&a[i]);
29 s[1]=a[1];
30 top=1;
31 for(i=2;i<=n;i++)
32 {
33 ans=find(a[i]);
34 s[ans]=a[i];
35 }
36 printf("%d\n",top);
37 }
38 return 0;
39 }