额,犹豫了半天,还是发出来了233
反正也没有人看对不233
T1
题目大意:给定三场比赛的排名 (1 ~ n),问有多少对 i,j 使得存在 i 的排名比 j 高和 j 的排名比 i 高的比赛
一眼看去是个三维偏序对不对,然后直接上 cdq 就 T 了不是….
嘛,其实可以算 (a,b),(a,c),(b,c),(b,a),(c,a),(c,b),其中 (a,b) 代表在比赛 a 的排名更高,比赛 b 的排名更低的队伍有多少对,然后除以 4 就好了…
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#define N 200005
using namespace std;
int n;
long long ans;
int a[N],b[N],c[N],t[N],T[N];
void add(int x,int c)
{
for (;x <= n;x += x & -x) T[x] += c;
}
int query(int x)
{
int ret = 0;
for (;x;x ^= x & -x) ret += T[x];
return ret;
}
void work(int *a,int *b)
{
memset(T,0,sizeof(T));
for (int i = 1;i <= n;i ++) t[a[i]] = b[i];
for (int i = 1;i <= n;i ++)
ans += i - 1 - query(t[i]),add(t[i],1);
}
int main()
{
freopen("contest.in","r",stdin);
freopen("contest.out","w",stdout);
scanf("%d",&n);
for (int i = 1;i <= n;i ++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
work(a,b),work(b,c),work(a,c);
work(b,a),work(c,b),work(c,a);
cout << ans / 4 << endl;
return 0;
}
T2
题目大意:给定并排的 n 条河流,每条河流有流速 v[i],你划船的速度为 u,并且给定了每条河的宽度 wi 和总时间,求离开最远点的距离
其实就是求
Δy
最大,设每段的时间为
xi
,则
wi
对
xi
取导后的值相等,设为
λ
,而
λ
一定
∑x
也一定,且成反比,所以就可以二分
λ
来判断啦
其中要注意二分的范围
而且要用 long double
#include<iostream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#define D long double
using namespace std;
int n;D u,t,sum,l,r;
D w[55],v[55];
D as[55];
bool check(D l)
{
D ans = 0;
for (int i = 1;i <= n;i ++)
{
D tmp = u * u * w[i] * w[i];
tmp /= (l - v[i]) * (l - v[i]) - u * u;
tmp = sqrt((tmp + w[i] * w[i]) / u / u);
if (tmp <= w[i] / u) return false;
ans += tmp;
if (ans > t) return true;
}
return false;
}
D cal(D l)
{
D ans = 0;
for (int i = 1;i <= n;i ++)
{
D tmp = u * u * w[i] * w[i];
tmp /= (l - v[i]) * (l - v[i]) - u * u;
tmp = sqrt((tmp + w[i] * w[i]) / u / u);
as[i] = tmp;
ans += sqrt(u * u * tmp * tmp - w[i] * w[i]) + tmp * v[i];
}
return ans;
}
int main()
{
freopen("river.in","r",stdin);
freopen("river.out","w",stdout);
cin >> n >> u >> t;
for (int i = 1;i <= n;i ++)
cin >> w[i] >> v[i],l = max(l,v[i]),sum += w[i];
if (sum / u > t) {puts("-1");return 0;}
l += u,r = 1e7;
for (int i = 1;i <= 100;i ++)
{
D mid = (l+r) * .5;
if (check(mid)) l = mid;
else r = mid;
}
D y = cal(l);
printf("%.3f\n",(double)sqrt(y*y + sum*sum));
for (int i = 1;i <= n;i ++) printf("%.3f ",(double)as[i]);
return 0;
}
T3
题目大意:给出一棵树和一些帮派,帮派的控制范围是由一些点和这些点之间的路径组成的。每次询问的时候给出一个点和一些帮派,求这个点到这些帮派控制范围的距离。
假如只有一个帮派,那么有三种情况
1)帮派为这个点的子树,那么求帮派的lca就好了
2)帮派包含了这个点,那么答案为0
3)这个点在lca的子树中,且未被包含,那么如果将帮派里的点按dfs序排序,那么找到与它相邻的两个点,取个距离的最小值就可以了
现在考虑多个帮派
先对每一个帮派按上述方法求一次,现在要求帮派之间的贡献,其实每个帮派取一个点就好了。
真·noip模拟题orz
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<vector>
#define N 500005
#define INF 1000000000
using namespace std;
int n,m,q,siz,tot,x,y,w,V,ans;
int first[N],next[N*2],to[N*2];
int num[N],lca[N],d[N],p[N],g[N][20];
vector <int> v[N];
void inser(int x,int y)
{
next[++ siz] = first[x];
first[x] = siz;
to[siz] = y;
}
void dfs(int x)
{
num[x] = ++ tot;
for (int i = first[x];i;i = next[i])
if (to[i] ^ g[x][0])
{
g[to[i]][0] = x,d[to[i]] = d[x] + 1;
for (int k = 0;g[x][k];k ++)
g[to[i]][k + 1] = g[g[to[i]][k]][k];
dfs(to[i]);
}
}
int LCA(int x,int y)
{
if (d[x] < d[y]) swap(x,y);
for (int i = 18;~i;i --)
if (d[g[x][i]] >= d[y]) x = g[x][i];
if (x == y) return x;
for (int i = 18;~i;i --)
if (g[x][i] ^ g[y][i])
x = g[x][i],y = g[y][i];
return g[x][0];
}
bool cmp(const int &a,const int &b)
{
return num[a] < num[b];
}
int main()
{
freopen("alliances.in","r",stdin);
freopen("alliances.out","w",stdout);
scanf("%d",&n);
for (int i = 1;i < n;i ++)
{
scanf("%d%d",&x,&y);
inser(x,y),inser(y,x);
}
dfs(d[1] = 1);
scanf("%d",&m);
for (int i = 1;i <= m;i ++)
{
scanf("%d",&w);
for (int j = 1;j <= w;j ++)
scanf("%d",&x),v[i].push_back(x);
sort(v[i].begin(),v[i].end(),cmp);
lca[i] = v[i][0];
for (int j = 1;j < w;j ++)
lca[i] = LCA(lca[i],v[i][j]);
}
scanf("%d",&q);
while (q --)
{
scanf("%d%d",&V,&w),ans = INF;
for (int i = 1;i <= w;i ++)
{
scanf("%d",&x),p[i] = v[x][0];
if (LCA(lca[x],V) ^ lca[x]) {ans = min(ans,d[lca[x]] + d[V] - 2 * d[LCA(lca[x],V)]);continue;}
int l = 0,r = v[x].size();
while (l < r - 1)
{
int mid = l+r >> 1;
if (num[v[x][mid]] <= num[V]) l = mid;
else r = mid;
}
ans = min(ans,d[V] - d[LCA(V,v[x][l])]);
if (r < v[x].size()) ans = min(ans,d[V] - d[LCA(V,v[x][r])]);
}
x = p[1];
for (int i = 2;i <= w;i ++) x = LCA(x,p[i]);
sort(p + 1,p + w + 1,cmp);
if (LCA(x,V) ^ x) {printf("%d\n",min(ans,d[x] + d[V] - 2 * d[LCA(x,V)]));continue;}
int l = 1,r = w + 1;
while (l < r - 1)
{
int mid = l+r >> 1;
if (num[p[mid]] <= num[V]) l = mid;
else r = mid;
}
ans = min(ans,d[V] - d[LCA(V,p[l])]);
if (r <= w) ans = min(ans,d[V] - d[LCA(V,p[r])]);
printf("%d\n", ans);
}
return 0;
}
什么时候开始贴代码了2333