T1 刺客信条
分析
这道题当时做的时候想到了二分的做法,但是没想出来怎么二分。所以华丽的爆0了。
那么我们考虑二分距离,把每个人抽象成一个圆(为什么不是方形呢?方形的顶点到中心的距离和方形的边上一点到照片中心的距离各不相同),这个圆的半径r就是我们要二分的。
当我们枚举到(0,0)和(x,y)之间,存在一个r使得圆相交(即我们不能走过),我们缩小r。
Code
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
struct xx {
double x,y;
}a[2005];
double dis[2005][2005], can[2005][4];
double h, w, n, Max = 0;
bool is[2005], flag;
double times(double x)
{
return x * x;
}
bool Run1(int now,double d)
{
if(can[now][1] <= d) return 1;
if(can[now][2] <= d) return 1;
is[now] = 1;
for (int i = 1; i <= n; i++)
{
if(dis[now][i]<=4*times(d) && is[i] == 0)
if(Run1(i, d)) return 1;
}
return 0;
}
bool Run2(int now,double d)
{
if(can[now][1] <= d) return 1;
if (can[now][2] <= d) return 1;
is[now] = 1; for (int i = 1; i <= n; i++)
{
if (dis[now][i] <= 4 * times(d) && is[i] == 0)
if (Run2(i, d)) return 1;
}
return 0;
}
int main()
{
scanf("%lf%lf%lf",&h,&w,&n);
for (int i = 1; i <= n; i++)
{
scanf("%lf%lf",&a[i].x,&a[i].y);
can[i][0] = a[i].x;
can[i][1] = a[i].y;
can[i][2] = h - a[i].x;
can[i][3] = w - a[i].y;
Max = max(Max,max( max(a[i].x,a[i].y), max(h - a[i].x,w - a[i].y) ));
}
for (int i = 1; i < n; i++)
for (int j = i+1; j <= n; j++)
{
double dx = a[i].x - a[j].x;
double dy = a[i].y - a[j].y;
double d = times(dx) + times(dy);
dis[i][j] = d; dis[j][i] = d;
}
double l = 0,r = Max;
r += 1;
while (l + 0.0001 < r)
{
flag = 0;
memset(is,0,sizeof(is));
double mid = (l + r) / 2;
for (int i = 1; i <= n; i++)
{
if (can[i][0] <= mid && is[i] == 0)
{
if (Run1(i,mid))
{
r = mid;
flag = 1;
break;
}
}
}
if (flag == 1)
continue;
memset(is,0,sizeof(is));
for(int i = 1; i <= n; i++)
{
if (can[i][3] <= mid && is[i] == 0)
{
if (Run2(i,mid))
{
r = mid;
flag = 1;
break;
}
}
}
if (flag == 1) continue;
l = mid;
}
printf("%.2lf",l);
return 0;
}
T3 传送门
分析
我们不妨设1为根。首先我们可以肯定的是,最优走法一定是在祖先设置好了传送门,在某个后代遍历完了以后传回来。如果没有传送门,时间显然是边权*2。所以我们有:如果当前节点有传送门,从它的某个子树中传了回来,再次走入这个子树一定不会更优。换句话说,一个传送门的某个子树只有遍历完了才会传回来。
那么我们设我们设f[i][0]为i结点的祖宗没有传送门,那么他就是下面的一条链只用走一次。f[i][1]为这个点有传送阵,儿子可以随便用,所以就等于所有子节点走到他的距离。
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int MAXN = 1e6+5;
int n, m;
int Weight[2*MAXN], To[2*MAXN], Head[MAXN], Next[2*MAXN];
long long f[MAXN][2], des[MAXN];
void AddEdge(int x, int y, int z)
{
Next[++m] = Head[x];
Head[x] = m;
To[m] = y;
Weight[m] = z;
}
void dfs(int k, int fa)
{
f[k][0] = f[k][1] = 0;
long long v = 0;
for(int i = Head[k]; i; i = Next[i])
{
int p = To[i];
if(p != fa)
{
dfs(p, k);
f[k][1] = f[k][1] + f[p][1] + 2 * Weight[i];
f[k][0] = f[k][0] + min(2*Weight[i]+f[p][0], f[p][1]+Weight[i]-des[p]);
des[k] = max(des[k], des[p]+Weight[i]);
}
}
}
int main()
{
cin >> n;
for(int i=1;i