20160730 训练记录
1.point
【题目大意】
求一个凸多边形内部(包括边界)的点,使得这个点到n个点的距离平方和最小。给定n个点的坐标以及凸多边形m个点的坐标。
$ n \leq 10^5, m \leq 5 \times 10^3$
【题解】
很明显推推公式我们发现,当点在(px, py)时,距离和最小,其中px为这n个点x坐标平均值,py为y坐标平均值。
那么我们判断这个点是否在凸多边形内
如果不在,我们求这个点到凸多边形各条边的距离,取最小值。那么所交的点即为最终答案的点。
# include <stdio.h> # include <cmath> # include <algorithm> using namespace std; const long double eps = 1e-10, meps = -eps; int X, Y; struct points { long double x, y; points () {} points (double _X, double _Y) : x(_X), y(_Y) {} points operator - (points A) { return points(x - A.x, y - A.y); } long double operator * (points A) { return x * A.y - y * A.x; } }p[100010], q[6060], pnt, pnt2; int n, m; long double sx, sy; long double dist = 1e90; inline long double sqr(long double x) { return x*x; } inline long double getdis(points a, points b) { return sqr(a.x - b.x) + sqr(a.y - b.y); } inline long double ldmin(long double a, long double b) { return a<b?a:b; } inline long double ldabs(long double x) { return x<0?-x:x; } inline bool iszero(long double x) { return fabs(x) < eps; } int main() { freopen("point.in", "r", stdin); freopen("point.out", "w", stdout); sx = 0, sy = 0; scanf("%d", &n); for (int i=1; i<=n; ++i) { scanf("%d%d", &X, &Y); p[i].x = (long double)X, p[i].y = (long double)Y; sx = sx + X, sy = sy + Y; } scanf("%d", &m); for (int i=1; i<=m; ++i) { scanf("%d%d", &X, &Y); q[i].x = (long double)X, q[i].y = (long double)Y; } pnt.x = 1.0 * sx / n; pnt.y = 1.0 * sy / n; bool ok=1; for (int i=1; i<=m; ++i) { int next = i%m+1; double res = (q[i] - q[next]) * (pnt - q[next]); if(res < 0) { ok=0; break; } } if(ok) { long double S = 0; for (int i=1; i<=n; ++i) S += getdis(pnt, p[i]); printf("%.10lf\n", (double)S); } else { for (int i=1; i<=m; ++i) { int next = i%m+1; points a = q[i], b = q[next]; long double A = getdis(a, pnt), B = getdis(b, pnt), C = getdis(a,b); if(A >= B+C || B >= A+C) { if(A < dist) dist = A, pnt2 = a; if(B < dist) dist = B, pnt2 = b; continue; } points pnt3; if(iszero(a.x - b.x)) { pnt3.y = pnt.y; pnt3.x = a.x; } else if(iszero(a.y - b.y)) { pnt3.x = pnt.x; pnt3.y = a.y; } else { long double kx = (b.y - a.y) / (b.x - a.x), ky = (-1.0)/kx; long double bx = a.y - kx * a.x, by = pnt.y - ky * pnt.x; pnt3.x = (by - bx) / (kx - ky); pnt3.y = kx * pnt3.x + bx; } long double Dist = getdis(pnt3, pnt); if(Dist < dist) { dist = Dist; pnt2 = pnt3; } } long double S = 0; for (int i=1; i<=n; ++i) S += getdis(pnt2, p[i]); printf("%.10lf\n", (double)S); } return 0; }
2.table
【题目大意】
给出一个n*m只包含01的矩阵,给出一个数k。
求当改变次数不超过k的时候,最少花多少次改变能使得这个矩阵的任意一个0或1的极大联通块都是矩形。改变意为,把一个元素0变为1,1变为0.
多组数据,$ T \leq 50, n,m \leq 100, k \leq 10$
【题解】
观察到k很小,那么我们假设k<n,那么一定有一行没有被改变。我们枚举哪一行没有被改变,然后往上往下贪心寻找(因为要使得极大连通块为矩形,第i行和枚举的那行要么相等要么互反)即可。如果k>=n那么我们枚举第一行的情况贪心往下推也可以
时间复杂度$O(n^3)$或$O(n^2 \times n!)$
# include <stdio.h> # include <algorithm> # include <iostream> using namespace std; int T, n, m, K, map[110][110], mp2[110][110], ans; int a[110]; inline void greedy() { int cur = 0; for (int i=1; i<=m; ++i) cur += (a[i] != map[1][i]); if(cur > K || cur > ans) return ; for (int i=2; i<=n; ++i) { int s1=0, s2=0; for (int j=1; j<=m; ++j) s1 += (map[i][j] != a[j]), s2 += (map[i][j] == a[j]); cur += min(s1, s2); } if(cur < ans) ans = cur; } inline void dfs(int step, int end) { if(step == end+1) { greedy(); return ; } a[step] = 1; dfs(step+1, end); a[step] = 0; dfs(step+1, end); } int main() { freopen("table.in", "r", stdin); freopen("table.out", "w", stdout); scanf("%d", &T); while(T--) { ans = 0x7fffffff; scanf("%d%d%d", &n, &m, &K); for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) scanf("%d", &map[i][j]); if (n < m) { for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) mp2[j][i] = map[i][j]; swap(n, m); for (int i=1; i<=n; ++i) for (int j=1; j<=m; ++j) map[i][j] = mp2[i][j]; } if (n > K) { for (int i=1; i<=n; ++i) { int cur = 0; for (int j=1; j<=n; ++j) { int s1=0, s2=0; for (int k=1; k<=m; ++k) s1 += (map[j][k] != map[i][k]); for (int k=1; k<=m; ++k) s2 += (map[j][k] == map[i][k]); cur += min(s1, s2); } if(cur < ans) ans = cur; } if(ans != 0x7fffffff && ans <= K) printf("%d\n", ans); else puts("-1"); } else { dfs(1, m); if(ans != 0x7fffffff && ans <= K) printf("%d\n", ans); else puts("-1"); } } return 0; }
3. company
【题目大意】
zy有一个公司,有n个员工,m条指令。一开始所有员工没有上级。
指令分为:
1. 1 x y:使y成为x的直接上司(保证之前x没有直接上司),且关系不构成环。
2. 2 x:zy发给员工x一份文件,员工x阅读完会传给他的直接上司阅读,他的直接上司阅读完会继续往上传,以此类推。
3. 3 x i:询问第i份文件是否被第x个人阅读过。
$ n \leq 2 \times 10^5, m \leq 4 \times 10^5$
【题解】
很明显离线处理
我们发现询问结果为YES,只有可能是满足下列两个条件
1. 在第i份文件传下去的时刻,传下去的人y和被询问的人x联通
2. 被询问的人x是传下去的人y的上司
第一个关系我们用并查集维护即可。第二个关系我们可以用LCA维护。
时间复杂度$O((n+m)logn)$。
当然我们可以用更快捷的DFS序维护。
# include <stdio.h> # include <algorithm> using namespace std; int n, m; struct quest { int opt, q1, q2, id; }q[666666], p[666666]; int gn=0, pn=0; int fa[666666]; int head[1666666],next[1666666],to[1666666],tot=0; int f[666666][20]; int level[666666]; int ans[666666]; bool havess[666666]; int root; inline int getf(int x) { return x == fa[x] ? fa[x] : fa[x] = getf(fa[x]); } inline bool cmp(quest a, quest b) { return a.q2 < b.q2; } inline void add(int x,int y) { tot++; next[tot]=head[x]; head[x]=tot; to[tot]=y; } void dfs(int x,int lev) { level[x]=lev; for (int i=1;i<=19;++i) f[x][i]=f[f[x][i-1]][i-1]; for (int i=head[x];i;i=next[i]) { if(!level[to[i]]) { f[to[i]][0]=x; dfs(to[i],lev+1); } } } inline int lca(int u,int v) { if (level[u]>level[v]) {int t=u;u=v;v=t;} for (int i=19;i>=0;--i) if(level[f[v][i]]>=level[u]) v=f[v][i]; if(u==v) return v; for (int i=19;i>=0;--i) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return f[u][0]; } int main() { freopen("company.in", "r", stdin); freopen("company.out", "w", stdout); scanf("%d%d", &n, &m); pn=0; for (int i=1; i<=n; ++i) fa[i] = i, level[i] = 0; for (int i=1; i<=m; ++i) { q[i].id = i; scanf("%d", &q[i].opt); if(q[i].opt == 3) { scanf("%d%d", &q[i].q1, &q[i].q2); p[++pn] = q[i]; p[pn].id = pn; ans[pn] = 0; } if(q[i].opt == 2) { scanf("%d", &q[i].q1); q[i].id = ++gn; } if(q[i].opt == 1) { scanf("%d%d", &q[i].q1, &q[i].q2); havess[q[i].q1] = 1; //printf("%d\n", q[i].q1); add(q[i].q1, q[i].q2); add(q[i].q2, q[i].q1); } } root = n+1; for (int i=1; i<=n; ++i) if(!havess[i]) { add(root, i); add(i, root); } dfs(root, 1); sort(p+1, p+pn+1, cmp); int cur = 1; for (int i=1; i<=m; ++i) { if(q[i].opt == 1) fa[q[i].q1] = q[i].q2; if(q[i].opt == 2) { for (; cur <= pn && p[cur].q2 == q[i].id; ++cur) { if(getf(p[cur].q1) == getf(q[i].q1)) { int LCA = lca(p[cur].q1, q[i].q1); if(LCA == p[cur].q1) ans[p[cur].id] = 1; } } } } for (int i=1; i<=pn; ++i) if(ans[i]) puts("YES"); else puts("NO"); return 0; }
2023年6月17日 13:54
When I applied for internet banking, I supplied my phone number. However, nothing has changed in my account. My e-banking account was temporarily frozen, and I needed to change my password.Overseas Indian Bank My mobile edutec.in number is being updated, and online banking is enabled on my account. When I applied for internet banking, I supplied my phone number. However, nothing has changed in my account. My e-banking account was temporarily frozen, and I needed to change my password. Overseas Indian Bank My mobile number is being updated, and online banking is enabled on my account.