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 };

完结撒花~

时间: 2024-10-12 14:48:27

Topcoder SRM 604 div1题解的相关文章

Topcoder SRM 607 div1题解

好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数据满足字符最多2500个. 我们考虑每一个子串,它对答案的贡献度就是它是回文串的概率,那么我们扫一遍就可以了, 这样做时间复杂度O(n^3),显然过不去. 我们考虑一下对于一个子串,在判断其是回文串的时候,我们一定是从中间往两边扫的,那么其实中间这些子串我们已经统计过答案了, 也就是说,我们通过枚举

Topcoder SRM 603 div1题解

昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点,每个节点都有一个权值,两人A和B分别进行操作,由A先手,每人可以选择一条边,将它删掉得到两个联通块.游戏不断进行下去,最后只剩下一个节点.A希望最后的节点权值尽可能大,B希望尽可能小,求这个最后的值.数据保证n<=50. 这道题真的是博弈好题啊-(感觉放到ACM很合适啊) 我们考虑第一次A会如何选

Topcoder SRM 608 div1 题解

Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需要选择多少个盒子.数据满足n<=50. 首先第一个方面,如果我们选择的盒子的下限大于等于X,那么显然我们一定可以获得那么多的苹果, 所以我们将盒子的下限排序,然后从大到小累加即可. 另一方面,如果我们没有选择的盒子的上限小于等于S-X,那么显然我们也一定可以获得那么多的苹果, 于是我们再按照上限排序

Topcoder SRM 605 div1 题解

日常打卡- Easy(250pts): 题目大意:你有n种汉堡包(统统吃掉-),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的个数)乘积越大,输出这个最大值.数据满足n<=50,type<=100,abs(taste)<=100000. 这题好像是个贪心,才不是呢啊哼- 首先我们发现,如果若干个汉堡包有同一个type值,那么我们可以把这一些汉堡包看成一个新的大汉堡包,它的type就是原来的type,它的taste就

Topcoder SRM 643 Div1 250&lt;peter_pan&gt;

Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*......*pn,我们假设p0,p1,...,pn是单调不降的,那么v里存储的是下标为偶数 的N的质因数p0,p2,p4,...,p(2k).现在要求写一个程序,返回一个vector<long long>ans; ans里存储的是p0,p1,p2,...,pn. Limits Time Limit(m

Topcoder SRM 648 Div1 250

Problem 给一个长度为N的"AB"字符串S,S只含有两种字符'A' 或 'B',设pair(i,j)(0=<i<j<N)表示一对 i,j 使得S[i]='A',S[j]='B'.现给定一个K,求字符串S,使得pair(i,j)的个数恰好为K.若不存在,则返回空串. Limits Time Limit(ms): 2000 Memory Limit(MB): 256 N: [2, 50] K: [0 , N*(N-1)/2 ] Solution 若K>(N/2

Topcoder SRM 627 div1 HappyLettersDiv1 : 字符串

Problem Statement      The Happy Letter game is played as follows: At the beginning, several players enter the field. Each player has a lowercase English letter on their back. The game is played in turns. In each turn, you select two players with dif

Topcoder SRM 662 DIV1

FoxesOfTheRoundTable 题意: 给你一个序列,让你生成一个排列,并且这个排列是循环的.使得任意两个相邻数的差的最大值尽量小. 题解: 先排个序,然后从小到大逐个插入.这时容易发现,若要得到最优的策略,只能将现在的这个数插在当前排列中最大的那个数的旁边,这是因为,要插入的这个数是大于当前排列中的任何一个数,故而插入只会产生一个更大的差距,为了使这个差距尽量小,就不得不在最大的数旁边插入. 假如现在的序列就是0 1 2 3 4 5 首先前三个数是没有影响的:0 1 2 插入3:0

topcoder srm 738 div1 FindThePerfectTriangle(枚举)

Problem Statement      You are given the ints perimeter and area. Your task is to find a triangle with the following properties: The coordinates of each vertex are integers between 0 and 3000, inclusive. The perimeter of the triangle must be exactly