1006 MEX
题意
见代码
思路
见代码
代码
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=5e5+5,M=2*N;
// n个结点(1-n)的树 再给定n-1条边 1号结点为根结点
// 每个结点有一个权值但未知 并且互不相同 定义每个结点的bi值为 MEX{ 以结点i为根的子树的所有点的权值的集合 }
// MEX{A} 求的是 不在集合A中的最小自然数
// 问 所有结点的bi值的和 最大为多少
// 求解思路:可以推断 要使得总的bi的和最大 某根节点的子树应该填充好0-n-2的权值 然后根节点填n-1 这样根节点bi一定是最大
// 这时根节点的bi 就为n 其实也是以它为根的子树的结点数量
// 然后因为权值互不相同 从0开始向上填权值只能在一颗子树内做到 此时其它子树结点的bi都是0 所以可以求得
// sum[root] = sz[root] + max(sum[某子结点]) sum[i]表示以i为根的树的所有结点bi值的最大和 sz[i]表示以i为根的子树结点数量
int h[N], e[M], ne[M], idx;
int sz[N];
long long sum[N];
void add(int a, int b)
{
e[idx] = b;
ne[idx] = h[a];
h[a] = idx++;
}
// 注意这种用图存储的树的遍历 一般要带一个父节点进行
int dfs(int u, int fa) //遍历以fa为父节点的 u结点子树的结点数量
{
sz[u] = 1;
for(int i = h[u]; i!=-1; i=ne[i]){
int j = e[i];
if(j == fa) continue; // 注意不要回到父节点
sz[u] += dfs(j, u); // 加上子树的结点数量
}
return sz[u];
}
int dp(int u, int fa) //求以u为根节点的子树 (fa是u的父节点) 所有结点的mex和最大值
{
sum[u] = 1; //初始化为1
for(int i = h[u]; i!=-1; i=ne[i]){
int j = e[i];
if(j == fa) continue; //注意不要回到父节点
dp(j, u);
sum[u] = max(sum[u], sz[u] + sum[j]); //将子树填0-n-2 自己就是n-1 那么自己的bi值就是n 其实就是子树结点数量
// 然后加上某颗子树的bi值的和就是总的bi值 为什么是某一棵子树呢 因为要想bi值和最大 必须一颗一颗子树按照顺序填满
// 这样可以发现 当某一课子树是从0开始填上去的 其它子树的bi值都是0
// 所以某个子树最大bi值之和就是 sum[root] = sz[root] + max(sum[某子结点])
}
return sum[u];
}
int main()
{
int t;
scanf("%d", &t);
while(t--){
idx = 0;
int n;
scanf("%d", &n);
memset(h, -1, sizeof(h));
for(int i = 1; i<n; i++){
int a, b;
scanf("%d%d", &a,&b);
add(a, b), add(b, a);
}
dfs(1, 0); // 先求sz数组
long long res = dp(1, 0);
printf("%lld\n", res);
}
return 0;
}
1012 Loop
题意
给定n个数,给定k次操作,每次将一个数提出来插到后面,问k次操作之后,数组按照字典序最大排列是什么?
思路
遇到什么情况将k提出来会使得排列字典序变大? 那就是ai < ai+1 的情况,这时我提出来ai,ai+1往前移动,那么由于ai+1>ai,排列的字典序一定会变大,所以我们只要保证将k个这种情况找到,提出来这些数,然后再由大到小考虑插在后面哪里,每一个数插在哪里可以用归并。
代码
#include<bits/stdc++.h>
using namespace std;
const int M=3e5+9;
int a[M];
int aaa[M];
int bbb[M];
void work(){
int n, k;
scanf("%d%d",&n,&k);
for(int i=0;i<n;++i) scanf("%d",&a[i]);
priority_queue<int>aa;
stack<int>ss;
for(int i = 0; i<n; i++){
while(ss.size() && ss.top() < a[i] && k){ // 维护一个单调栈
aa.push(ss.top());
ss.pop();
k--;
}
ss.push(a[i]);
}
// 上面维护完之后 aa里面就是要提出来的k个数
// ss是除了这k个数以外的原数组其它数的逆序
int i; // 将两个容器转存到普通数组
int na = ss.size();
for(i = na-1 ; i>=0; i--){ //注意栈是逆序过来才是原数组顺序
aaa[i] = ss.top();
ss.pop();
}
int nb = aa.size();
for(i = 0 ; i<nb; i++){
bbb[i] = aa.top();
aa.pop();
}
int ia,ib; // 归并
int cnt = 1;
for(ia = 0, ib = 0; ia<na && ib<nb; ){
if(aaa[ia] >= bbb[ib]){
if(cnt++ == n) cout<<aaa[ia++];
else cout<<aaa[ia++]<<" ";
}
if(aaa[ia] < bbb[ib]){
if(cnt++ == n) cout<<bbb[ib++];
else cout<<bbb[ib++]<<" ";
}
}
while(ia < na) {
if(cnt++ == n) cout<<aaa[ia++];
else cout<<aaa[ia++]<<" ";
}
while(ib < nb) {
if(cnt++ == n) cout<<bbb[ib++];
else cout<<bbb[ib++]<<" ";
}
cout<<endl;
}
int main(){
int T;
scanf("%d",&T);
while(T--) work();
return 0;
}
/*
2
7 3
1 4 2 1 4 2 4
5 2
4 3 5 4 5
*/
1009 不动点
题意
小地图abcd是大地图ABCD按照原尺寸缩小而来,然后将它放在大地图里面,一定有一个点,它既是大地图这个位置的点,又是小地图这个位置上的点, 求这个点。
思路
不动点定理,用向量求解,设出P点坐标,然后将OP = OA + AP = OA + p*AB + q*AD = oa + aP = oa + p * ab + q * ad。 用x和y两个分量 ,可以列两个方程,然后求解p q,就可以得到P坐标。
代码
#include<cstdio>
#include<iostream>
#include<cmath>
using namespace std;
long double dis(double x1, double y1, double x2, double y2, double x0, double y0)
{
long double d = (fabs((y2 - y1) * x0 +(x1 - x2) * y0 + ((x2 * y1) -(x1 * y2)))) / (sqrt(pow(y2 - y1, 2) + pow(x1 - x2, 2)));
return d;
}
int main()
{
int t;
scanf("%d", &t);
double Ax, Bx, Cx, Dx;
double Ay, By, Cy, Dy;
double ax, bx, cx, dx;
double ay, by, cy, dy;
while(t--){
scanf("%lf%lf", &Ax, &Ay);
scanf("%lf%lf", &Bx, &By);
scanf("%lf%lf", &Cx, &Cy);
scanf("%lf%lf", &Dx, &Dy);
scanf("%lf%lf", &ax, &ay);
scanf("%lf%lf", &bx, &by);
scanf("%lf%lf", &cx, &cy);
scanf("%lf%lf", &dx, &dy);
double ABx = Ax - Bx, ABy = Ay - By;
double abx = ax - bx, aby = ay - by;
double X1 = ABx - abx, Y1 = ABy - aby;
double ADx = Ax - Dx, ADy = Ay - Dy;
double adx = ax - dx, ady = ay - dy;
double X2 = ADx - adx, Y2 = ADy - ady;
double X3 = ax - Ax, Y3 = ay - Ay;
// pX1 + qX2 = X3
// pY1 + qY2 = Y3 * (X1/Y1)
double q = (X1*Y3 - X3*Y1) / (Y2*X1 - X2*Y1);
double p = (X3 - q*X2) / X1;
double PX = Ax + p*ABx + q*ADx;
double PY = Ay + p*ABy + q*ADy;
printf("%.6lf %.6lf\n", PX, PY);
}
return 0;
}