首页 > 代码库 > Topcoder SRM 604 div1题解

Topcoder SRM 604 div1题解

CTSC考完跑了过来日常TC~~~

Easy(250pts):

题目大意:有个机器人,一开始的位置在(0,0),第k个回合可以向四个方向移动3^k的距离(不能不动),问是否可以到达(x,y),数据满足|x|,|y|<=10^9。

这题还是很简单的嘛,口亨~~~

首先我们只考虑一个方向,于是发现,每一次可以移动3^k的距离或者不动,于是我们发现这样的序列是有且仅有一个的,

于是我们分开考虑x和y,把两个序列全部预处理出来,

然后直接扫一遍就做完了,

时间复杂度O(log|x|)左右吧,代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 class PowerOfThree
 4 {
 5     public:
 6     string ableToGet(int x, int y)
 7     {
 8         x=abs(x),y=abs(y);
 9         bool check=true;
10         while (x!=0||y!=0)
11         {
12             if ((x%3==0)+(y%3==0)!=1) check=false;
13             if (x%3==2) x=(x+1)/3; else x=x/3;
14             if (y%3==2) y=(y+1)/3; else y=y/3;
15         }
16         if (check) return "Possible"; else return "Impossible";
17     }
18 };

Medium(550pts):

题目大意:有一棵n个节点的树,有若干节点上有一只狐狸,其它节点没有,所有边的距离为1。现在狐狸要聚集在一起,使得它们形成了一棵树,且每个节点依然最多只有一只狐狸,且移动距离之和最小,输出这个最小值。数据满足n<=50。

我做过的最难的medium吧。。。这题做了我好久好久。。。

首先,最后形成的狐狸一定是一棵树,我们枚举每一个节点i,设i是最后这棵树的root,

我们考虑树形dp,

设f[i][j]表示i这个节点形成的子树中一共放置了j个狐狸,且i这个节点一定有狐狸,且这j个狐狸联通的最优值。

我们考虑如何转移,

假设cur[j]就是当前u这个节点已经处理了若干个儿子的f[u]数组,

于是我们能够得到f[u][i+j]就是从已经处理的若干个儿子中提取i个,从当前正在处理的v节点中提取j个的最优值,

那么已经处理完的若干个儿子对答案的贡献度是cur[i],当前处理的v节点对答案的贡献度是f[v][j]+(u和v这条边对答案的贡献度),

所以f[u][i+j]=cur[i]+f[v][j]+(u和v这条边对答案的贡献度),

所以我们只需要考虑这条边的贡献度就可以了,我们假设size[u]表示u这个节点为根的子树下原始状态下有多少个狐狸,

如果size[v]=j,那么这条边的贡献度就是0;

如果size[v]>j,那么一定有size[v]-j个狐狸从v这个子树出来,那么一定经过这条边,所以这条边贡献度就是size[v]-j;

如果size[v]<j,那么一定有j-size[v]个狐狸进入v这个子树中,它们也一定经过这条边,所以这条边的贡献度就是j-size[v]。

所以无论如何,这条边的贡献度一定是abs(size[v]-j)。

所以我们有f[u][i+j]=cur[i]+f[v][j]+abs(size[v]-j)。

然后边界细节注意一下就可以了,时间复杂度O(n^4),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxn 1007
 3 #define inf 1000000007
 4 using namespace std;
 5 int n,cnt,ans=inf,m;
 6 int last[Maxn],other[Maxn],pre[Maxn],sum[Maxn],size[Maxn];
 7 int f[2*Maxn][2*Maxn];
 8 int temp[4*Maxn];
 9 bool fox[Maxn];
10 class FoxConnection
11 {
12     void insert(int u, int v)
13     {
14         other[++cnt]=v,pre[cnt]=last[u],last[u]=cnt;
15     }
16     void dfs(int u, int fa)
17     {
18         size[u]=fox[u];
19         int cur[4*Maxn];
20         memset(cur,0,sizeof(cur));
21         for (int q=last[u];q;q=pre[q])
22         {
23             int v=other[q];
24             if (v!=fa)
25             {
26                 dfs(v,u);
27                 for (int i=0;i<=m;i++) temp[i]=inf;
28                 for (int i=0;i<=m;i++)
29                     for (int j=0;j<=m-i;j++)
30                         temp[i+j]=min(temp[i+j],cur[i]+f[v][j]+abs(size[v]-j));
31                 for (int i=0;i<=m;i++) cur[i]=temp[i];
32                 size[u]+=size[v];
33             }
34         }
35         f[u][0]=cur[0];
36         for (int i=1;i<=m;i++) f[u][i]=cur[i-1];
37     }
38     int solve(int rt)
39     {
40         for (int i=1;i<=n;i++)
41             for (int j=0;j<=2*n;j++)
42                 f[i][j]=inf;
43         dfs(rt,-1);
44         return f[rt][m];
45     }
46     public:
47     int minimalDistance(vector <int> A, vector <int> B, string haveFox)
48     {
49         n=A.size()+1;
50         for (int i=0;i<n;i++) fox[i+1]=(haveFox[i]==Y);
51         m=0;
52         for (int i=1;i<=n;i++) if (fox[i]) ++m;
53         for (int i=0;i<n-1;i++)
54             insert(A[i],B[i]),insert(B[i],A[i]);
55         for (int i=1;i<=n;i++)
56             ans=min(ans,solve(i));
57         return ans;
58     }
59 };

Hard(1000pts):

这个计算几何题怎么比medium思路简单多了呢。。。

题目大意:给了你n条线段,它们可能有交点,可能有重合,现在把它们视为一个模块,有一张10^9*10^9的长方形纸片,现在复制若干遍这个模块,要求任意两个模块不能相交,要求判断是否可以复制无穷多份。数据满足n<=50。

这题的思路还是很简单的吧,如果能够复制无数份,那么一定是能够往某个方向移动了很小很小的距离,

我们先把所有直线两两处理,

如果重合,直接不用管;

如果没有交点,直接不用管;

如果有一个交点,而且交点不是直线的端点,直接有穷个返回答案;

如果有一个交点,而且交点是直线的端点,那么那个方向一定有角度限制,预处理出角度限制。

所有直线两两处理完了之后,把所有角度限制从小到大扫一遍,然后判定一下就做完了。

时间复杂度O(n^2),代码如下:

 1 #include <bits/stdc++.h>
 2 #define eps 1e-9
 3 #define Maxn 107
 4 using namespace std;
 5 int n,cnt=0;
 6 struct point {double x,y;};
 7 struct line {point a,b;};
 8 line a[Maxn];
 9 pair<double,double> cover[Maxn*Maxn*2];
10 class FamilyCrest
11 {
12     double cross(double x1 ,double y1, double x2, double y2)
13     {
14         return (x1*y2-x2*y1);
15     }
16     bool samepoint(point a, point b)
17     {
18 //check if point a and point b are the same point
19         if (fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps) return true;
20         return false;
21     }
22     bool sameline(line a, line b)
23     {
24 //check if line a and line b are the same line
25         double res=cross(a.a.x-a.b.x,a.a.y-a.b.y,b.a.x-b.b.x,b.a.y-b.b.y);
26         if (fabs(res)<eps) return true;
27         return false;
28     }
29     double sameposition(line a, line b)
30     {
31 //check if the whole segment b is on the same direction of line a
32 //answer>0 means segment b is on the same direction of line a
33 //answer<0 means segment b has a same point with line a
34 //answer=0 means segment b has an end point on the line a
35         double res,res1,res2;
36         res1=cross(a.b.x-a.a.x,a.b.y-a.a.y,b.a.x-a.a.x,b.a.y-a.a.y);
37         res2=cross(a.b.x-a.a.x,a.b.y-a.a.y,b.b.x-a.a.x,b.b.y-a.a.y);
38         res=res1*res2;
39         return res;
40     }
41     void updata(double l, double r)
42     {
43         if (l<r)
44         {
45             cover[++cnt].first=l,cover[cnt].second=r;
46         } else
47         {
48             cover[++cnt].first=l,cover[cnt].second=M_PI;
49             cover[++cnt].first=-M_PI,cover[cnt].second=r;
50         }
51     }
52     bool calc(line a, line b)
53     {
54 //segment a and segment b are on the same line
55         if (sameline(a,b)) return true;
56 //segment a and segment b don‘t have a same point
57         if (sameposition(a,b)>eps) return true;
58         if (sameposition(b,a)>eps) return true;
59 //segment a and segment b have a same point which is not an end point
60         if (sameposition(a,b)<-eps) return false;
61         if (sameposition(b,a)<-eps) return false;
62 //segment a and segment b have a same point which is an end point
63         point O,A,B;
64 //point O is the end point
65         if (samepoint(a.a,b.a)) O=a.a,A=a.b,B=b.b; else
66         if (samepoint(a.a,b.b)) O=a.a,A=a.b,B=b.a; else
67         if (samepoint(a.b,b.a)) O=a.b,A=a.a,B=b.b; else
68         if (samepoint(a.b,b.b)) O=a.b,A=a.a,B=b.a;
69         if (cross(A.x-O.x,B.x-O.x,A.y-O.y,B.y-O.y)>eps) swap(A,B);
70         updata(atan2(A.y-O.y,A.x-O.x),atan2(O.y-B.y,O.x-B.x));
71         updata(atan2(O.y-A.y,O.x-A.x),atan2(B.y-O.y,B.x-O.x));
72         return true;
73     }
74     public:
75     string canBeInfinite(vector <int> A, vector <int> B, vector <int> C, vector <int> D)
76     {
77         n=A.size();
78         for (int i=1;i<=n;i++)
79         {
80             a[i].a.x=A[i-1];
81             a[i].a.y=B[i-1];
82             a[i].b.x=C[i-1];
83             a[i].b.y=D[i-1];
84         }
85         for (int i=1;i<=n;i++)
86             for (int j=i+1;j<=n;j++)
87                 if (!calc(a[i],a[j])) return "Finite";
88         sort(cover+1,cover+cnt+1);
89         if (cover[1].first+M_PI>eps) return "Infinite";
90         if (cover[cnt].second-M_PI<-eps) return "Infinite";
91         double now=cover[1].second;
92         for (int i=2;i<=cnt;i++)
93         {
94             if (cover[i].first-now>eps) return "Infinite";
95             now=cover[i].second;
96         }
97         return "Finite";
98     }
99 };

完结撒花~

 

Topcoder SRM 604 div1题解