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|)左右吧,代码如下:
#include <bits/stdc++.h>
using namespace std;
class PowerOfThree
{
public:
string ableToGet(int x, int y)
{
x=abs(x),y=abs(y);
bool check=true;
while (x!=||y!=)
{
if ((x%==)+(y%==)!=) check=false;
if (x%==) x=(x+)/; else x=x/;
if (y%==) y=(y+)/; else y=y/;
}
if (check) return "Possible"; else return "Impossible";
}
};
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),代码如下:
#include <bits/stdc++.h>
#define Maxn 1007
#define inf 1000000007
using namespace std;
int n,cnt,ans=inf,m;
int last[Maxn],other[Maxn],pre[Maxn],sum[Maxn],size[Maxn];
int f[*Maxn][*Maxn];
int temp[*Maxn];
bool fox[Maxn];
class FoxConnection
{
void insert(int u, int v)
{
other[++cnt]=v,pre[cnt]=last[u],last[u]=cnt;
}
void dfs(int u, int fa)
{
size[u]=fox[u];
int cur[*Maxn];
memset(cur,,sizeof(cur));
for (int q=last[u];q;q=pre[q])
{
int v=other[q];
if (v!=fa)
{
dfs(v,u);
for (int i=;i<=m;i++) temp[i]=inf;
for (int i=;i<=m;i++)
for (int j=;j<=m-i;j++)
temp[i+j]=min(temp[i+j],cur[i]+f[v][j]+abs(size[v]-j));
for (int i=;i<=m;i++) cur[i]=temp[i];
size[u]+=size[v];
}
}
f[u][]=cur[];
for (int i=;i<=m;i++) f[u][i]=cur[i-];
}
int solve(int rt)
{
for (int i=;i<=n;i++)
for (int j=;j<=*n;j++)
f[i][j]=inf;
dfs(rt,-);
return f[rt][m];
}
public:
int minimalDistance(vector <int> A, vector <int> B, string haveFox)
{
n=A.size()+;
for (int i=;i<n;i++) fox[i+]=(haveFox[i]=='Y');
m=;
for (int i=;i<=n;i++) if (fox[i]) ++m;
for (int i=;i<n-;i++)
insert(A[i],B[i]),insert(B[i],A[i]);
for (int i=;i<=n;i++)
ans=min(ans,solve(i));
return ans;
}
};
Hard(1000pts):
这个计算几何题怎么比medium思路简单多了呢。。。
题目大意:给了你n条线段,它们可能有交点,可能有重合,现在把它们视为一个模块,有一张10^9*10^9的长方形纸片,现在复制若干遍这个模块,要求任意两个模块不能相交,要求判断是否可以复制无穷多份。数据满足n<=50。
这题的思路还是很简单的吧,如果能够复制无数份,那么一定是能够往某个方向移动了很小很小的距离,
我们先把所有直线两两处理,
如果重合,直接不用管;
如果没有交点,直接不用管;
如果有一个交点,而且交点不是直线的端点,直接有穷个返回答案;
如果有一个交点,而且交点是直线的端点,那么那个方向一定有角度限制,预处理出角度限制。
所有直线两两处理完了之后,把所有角度限制从小到大扫一遍,然后判定一下就做完了。
时间复杂度O(n^2),代码如下:
#include <bits/stdc++.h>
#define eps 1e-9
#define Maxn 107
using namespace std;
int n,cnt=;
struct point {double x,y;};
struct line {point a,b;};
line a[Maxn];
pair<double,double> cover[Maxn*Maxn*];
class FamilyCrest
{
double cross(double x1 ,double y1, double x2, double y2)
{
return (x1*y2-x2*y1);
}
bool samepoint(point a, point b)
{
//check if point a and point b are the same point
if (fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps) return true;
return false;
}
bool sameline(line a, line b)
{
//check if line a and line b are the same line
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);
if (fabs(res)<eps) return true;
return false;
}
double sameposition(line a, line b)
{
//check if the whole segment b is on the same direction of line a
//answer>0 means segment b is on the same direction of line a
//answer<0 means segment b has a same point with line a
//answer=0 means segment b has an end point on the line a
double res,res1,res2;
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);
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);
res=res1*res2;
return res;
}
void updata(double l, double r)
{
if (l<r)
{
cover[++cnt].first=l,cover[cnt].second=r;
} else
{
cover[++cnt].first=l,cover[cnt].second=M_PI;
cover[++cnt].first=-M_PI,cover[cnt].second=r;
}
}
bool calc(line a, line b)
{
//segment a and segment b are on the same line
if (sameline(a,b)) return true;
//segment a and segment b don't have a same point
if (sameposition(a,b)>eps) return true;
if (sameposition(b,a)>eps) return true;
//segment a and segment b have a same point which is not an end point
if (sameposition(a,b)<-eps) return false;
if (sameposition(b,a)<-eps) return false;
//segment a and segment b have a same point which is an end point
point O,A,B;
//point O is the end point
if (samepoint(a.a,b.a)) O=a.a,A=a.b,B=b.b; else
if (samepoint(a.a,b.b)) O=a.a,A=a.b,B=b.a; else
if (samepoint(a.b,b.a)) O=a.b,A=a.a,B=b.b; else
if (samepoint(a.b,b.b)) O=a.b,A=a.a,B=b.a;
if (cross(A.x-O.x,B.x-O.x,A.y-O.y,B.y-O.y)>eps) swap(A,B);
updata(atan2(A.y-O.y,A.x-O.x),atan2(O.y-B.y,O.x-B.x));
updata(atan2(O.y-A.y,O.x-A.x),atan2(B.y-O.y,B.x-O.x));
return true;
}
public:
string canBeInfinite(vector <int> A, vector <int> B, vector <int> C, vector <int> D)
{
n=A.size();
for (int i=;i<=n;i++)
{
a[i].a.x=A[i-];
a[i].a.y=B[i-];
a[i].b.x=C[i-];
a[i].b.y=D[i-];
}
for (int i=;i<=n;i++)
for (int j=i+;j<=n;j++)
if (!calc(a[i],a[j])) return "Finite";
sort(cover+,cover+cnt+);
if (cover[].first+M_PI>eps) return "Infinite";
if (cover[cnt].second-M_PI<-eps) return "Infinite";
double now=cover[].second;
for (int i=;i<=cnt;i++)
{
if (cover[i].first-now>eps) return "Infinite";
now=cover[i].second;
}
return "Finite";
}
};
完结撒花~
Topcoder SRM 604 div1题解的更多相关文章
- Topcoder SRM 602 div1题解
打卡- Easy(250pts): 题目大意:rating2200及以上和2200以下的颜色是不一样的(我就是属于那个颜色比较菜的),有个人初始rating为X,然后每一场比赛他的rating如果增加 ...
- Topcoder SRM 607 div1题解
好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数 ...
- Topcoder SRM 608 div1 题解
Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需 ...
- Topcoder SRM 606 div1题解
打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...
- Topcoder SRM 605 div1 题解
日常打卡- Easy(250pts): 题目大意:你有n种汉堡包(统统吃掉-),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的 ...
- Topcoder SRM 603 div1题解
昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...
- Topcoder SRM 601 div1题解
日常TC计划- Easy(250pts): 题目大意:有n个篮子,每个篮子有若干个苹果和橘子,先任取一个正整数x,然后从每个篮子中选出x个水果,把nx个水果放在一起,输出一共有多少种不同的组成方案.其 ...
- Topcoder SRM 600 div1题解
日常TC计划正式启动! Easy(250pts): 题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数.问至少删去多少个数,使得你永远无法 ...
- Topcoder SRM 643 Div1 250<peter_pan>
Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*... ...
随机推荐
- php-5.6.26源代码 - 如何用C语言支持“类似异常”机制
代码编写在文件php-\Zend\zend.h #define zend_bailout() _zend_bailout(__FILE__, __LINE__) #ifdef HAVE_SIGSETJ ...
- 将Komodo Edit打造成Python开发的IDE
Komodo Edit 支持Python 界面清爽, 将Komodo Edit 设置成Python的IDE,具体操作方法如下: 先添加自定义命令. 再设置命令行参数 设置高级选项 设置快捷键 完成.
- python-8错误调试测试
1-错误处理 import logging try: print('try.......') r = 10/0 except ValueError as e: print('result:', e) ...
- Kettle资源库配置(数据库资源库和文件资源库)
一>文件资源库配置 1. 建立文件资源库:点击工具->资源库->连接资源库菜单 使用文件资源库不需要用户名和密码,如果没有资源库可以点击右上角的"+"新建资源库, ...
- 15 Django组件-中间件
中间件 中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好 ...
- Android 布局错乱 Android花屏
最近做项目,妈的,有个一个很难受的bug. 这个bug ,自己这里没有手机,没有办法复现,找到了手机之后.解决了. 我先给大家看下什么叫布局错乱,花屏: 来张正常的图片: 正常情况下是这样的.然后, ...
- ajax跨域请求_url:http://XXX
利用别的项目提供的一个接口,传入用户名和密码,根据返回的结果判断登陆成功与否. 不经过后台,在js中用ajax实现.对ajax而言,发送跨域请求,与一般写法不同. 如果支持jsonp,则将dataTy ...
- Java 多线程并发编程一览笔录
Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...
- Monkey、Monkeyrunner之间的区别
Monkey.Monkeyrunner之间的区别 一.Monkey Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中.它向系统发送伪随机的用户事件流(如按键输入.触摸屏输 ...
- Convert.ToBase64String(Byte[])和Encoding.UTF8.GetString(Byte[])的区别
Encoding.UTF8.GetString是针对使用utf8编码得到的字符串对应的byte[]使用,可以还原我们能看懂的字符串而Convert.ToBase64String是对任意byte[]都可 ...