Topcoder SRM 604 div1题解

Posted 一只蒟篛酱的日常~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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题解的主要内容,如果未能解决你的问题,请参考以下文章

Topcoder SRM 605 div1 题解

Topcoder SRM 603 div1题解

Topcoder SRM 608 div1 题解

Topcoder SRM 607 div1题解

TopCoder SRM502 Div1 1000 动态规划

topcoder srm 335 div1