杭电多校第六场个人补题6 7 9 10 12
6
题意
给定一棵有n结点的树,点权为1~n,求对所有结点子树的mex操作和的最大值
思路
其实就是从最底部开始网上找,由于0是唯一的一个,所欲最好给在最长链的底部,这样可以保证最大,所以就是一个dfs往上递归就行了,对于每一棵树都认为是最长链,往上跑取最大值就可以了。
代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
const double eps = 1e-9;
typedef pair<int, int> PII;
vector<int> g[N];
pair<int,int> dfs(int u, int f){
pair<int,int> res = {0, 1};
for(int v:g[u]){
if(v != f){
auto t = dfs(v, u);
res.first = max(t.first, res.first);
res.second += t.second;
}
}
res.first += res.second;
return res;
}
void solve(){
int n;
cin >> n;
for(int i = 1;i <= n;i++){
g[i].clear();
}
for(int i = 0;i < n - 1;i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
auto ans = dfs(1, 0);
cout << ans.first << "\n";
}
signed main() {
IOS;
int T = 1;
cin >> T;
while (T--) {
solve();
}
}
7
题意
给p个点,对于第t天,可以到达第 a t ∗ i m o d p a^t*i mod p at∗imodp个点,对于q次询问,给一个地点x,有n个旅行计划,从某一点出发,问在限定时间内有几个计划能到地点x
思路
**队友在比赛的时候第一反应是bsgs做,我不会就一直没看,最后写t了,之后看题解才发现就是一个思维题,首先我们可以注意一下对于n,q都是在1e3的范围内的,所以我们可以预处理一下a的所有次方,又由于取模时会有循环节,所以当访问到第一个循环节的时候就退出开始询问,唯一注意的是要预处理逆元,不然因为查询会t,另外要特别注意的是特判x=0的点 **
代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 998244353;
typedef pair<int, int> PII;
int p, a, n, q;
int qpow(int a, int b) {
int base = a, ans = 1;
while (b) {
if (b & 1) ans = ans * base % p;
base = base * base % p;
b >>= 1;
}
return ans % p;
}
unordered_map<int, int>mp;
void solve() {
cin >> p >> a >> n >> q;
mp.clear();
vector<PII>v(n + 1);
vector<int>ni(n+1);
for (int i = 1; i <= n; i++) {
cin >> v[i].first >> v[i].second;
if(v[i].first) ni[i]=qpow(v[i].first,p-2);
}
mp[1] = 0;
int pre = 1;
for (int i = 1; i <= 2e5+5; i++) {
if(mp.count(pre * a % p)==0) mp[pre * a % p] = i;
else break;
pre = pre * a % p;
}
while (q--) {
int x;
cin >> x;
int res = 0;
if (x == 0) {
for (int i = 1; i <= n; i++) {
if(v[i].first==0) res++;
}
} else {
for (int i = 1; i <= n; i++) {
int k = ni[i];
int l = k * x % p;
if (mp.count(l)&&mp[l]<=v[i].second) {
res++;
}
}
}
cout << res << endl;
}
}
signed main() {
IOS;
int t = 1;
cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
}
9
题意
两个相似的矩形,已知当两个矩形重叠的时候一定有一个点重合,问那个重合的点是多少
思路
比赛的时候第一反应是两个阿波罗尼斯圆的交点,然后判断哪个点在矩形内就完了,结果苦于没有计算几何的板子,好像一直都丢了精度,后来换了个板子过了(听说代数方法高斯消元也很简单,但是没学复变不会。。。)
代码
#include<bits/stdc++.h>
using namespace std;
//#define int long long
//#define double long double
const double eps = 1e-6;
struct Point {
double x, y;
Point(double x = 0, double y = 0): x(x), y(y) { } //构造函数
};
//!注意区分点和向量
typedef Point Vector;
//向量平移之后还是那个向量,所以只需要原点和向量的终点即可
//!向量 + 向量 = 向量,点 + 向量 = 向量
Vector operator + (Vector A, Vector B) {
return Vector(A.x + B.x, A.y + B.y);
}
//!点 - 点 = 向量(向量BC = C - B)
Vector operator - (Point A, Point B) {
return Vector(A.x - B.x, A.y - B.y);
}
//!向量 * 数 = 向量
Vector operator * (Vector A, double p) {
return Vector(A.x * p, A.y * p);
}
//!向量 / 数= 向量
Vector operator / (Vector A, double p) {
return Vector(A.x / p, A.y / p);
}
//!点/向量的比较函数
bool operator < (const Point& a, const Point& b) {
return a.x < b.x || (a.x == b.x && a.y < b. y);
}
//!求极角//在极坐标系中,平面上任何一点到极点的连线和极轴的夹角叫做极角。
//单位弧度rad
struct Circle {
Point c;
double r;
Circle(Point c = Point(), double r = 0): c(c), r(r) {}
inline Point point(double a) { //通过圆心角求坐标
return Point(c.x + cos(a) * r, c.y + sin(a) * r);
}
};
inline Circle read_circle() {
Circle C;
//scanf("%lf%lf%lf", &C.c.x, &C.c.y, &C.r);
return C;
}//!点积(满足交换律)
double Dot(Vector A, Vector B) {
return A.x * B.x + A.y * B.y;
}
int dcmp(double x, double y = 0) {
if (fabs(x - y) < eps)
return 0;
if (x > y)
return 1;
return -1;
}
bool operator == (const Point& a, const Point& b) {
return !dcmp(a.x - b.x) && !dcmp(a.y - b.y);
}
double Length(Vector A) {
return sqrt(Dot(A, A));
}
double Polar_angle(Vector A) {
return atan2(A.y, A.x);
}
//两圆相交保存所有交点返回交点个数(至多两个)
int get_circle_circle_intersection(Circle c1, Circle c2, vector<Point>& sol) {
double d = Length(c1.c - c2.c);
if (dcmp(d) == 0) {
if (dcmp(c1.r - c2.r) == 0)return -1; //两圆重合
return 0;
}
if (dcmp(c1.r + c2.r - d) < 0)return 0; //相离
if (dcmp(fabs(c1.r - c2.r) - d) > 0)return 0; //在另一个圆的内部
double a = Polar_angle(c2.c - c1.c);//向量c1c2的极角
double da = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d));
//c1c2到c1p1的角
Point p1 = c1.point(a - da), p2 = c1.point(a + da);
sol.push_back(p1);
if (p1 == p2)return 1;
sol.push_back(p2);
return 2;
}
int sgn(double x) {
if (fabs(x) < eps)
return 0;
if (x < 0)
return -1;
return 1;
}
Point a[4], b[4];
double k;
Circle getCircle(Point a, Point b) {
Vector tmp11, tmp22;
tmp11.x = a.x, tmp11.y = a.y;
tmp22.x = b.x, tmp22.y = b.y;
double dis2 = Length(tmp11 - tmp22);
Circle p2;
double len11 = dis2 / (k - 1) + dis2, len22 = dis2 - dis2 / (k + 1);
double lens = (len11 + len22) / 2;
double chax2 = b.x - a.x;
double zhenx2 = lens * chax2 / dis2 ;
double chay2 = b.y - a.y;
double zheny2 = lens * chay2 / dis2 ;
double banjin2 = (len11 - len22) / 2;
p2.c.x = zhenx2 + a.x, p2.c.y = zheny2 + a.y;
p2.r = abs(banjin2);
return p2;
}
bool InCircle(Circle p0, Point p) {
double dis = sqrt((p.x - p0.c.x) * (p.x - p0.c.x) + (p.y - p0.c.y) * (p.y - p0.c.y));
return sgn(dis - p0.r) == 0;
}
signed main() {
int t;
scanf("%d", &t);
while (t--) {
for (int i = 0; i < 4; i++) {
scanf("%lf %lf", &a[i].x, &a[i].y);
}
for (int i = 0; i < 4; i++) {
scanf("%lf %lf", &b[i].x, &b[i].y);
}
Vector tmp1, tmp2;
tmp1.x = a[0].x, tmp1.y = a[0].y;
tmp2.x = a[3].x, tmp2.y = a[3].y;
Vector tmp3, tmp4;
tmp3.x = b[0].x, tmp3.y = b[0].y;
tmp4.x = b[3].x, tmp4.y = b[3].y;
k = Length(tmp1 - tmp2) / Length(tmp3 - tmp4);
Circle p1 = getCircle(a[0], b[0]);
Circle p2 = getCircle(a[1], b[1]);
Circle p3 = getCircle(a[2], b[2]);
Circle p4 = getCircle(a[3], b[3]);
vector<Point> sol;
get_circle_circle_intersection(p1, p2, sol);
for (auto x : sol) {
if (InCircle(p3, x) == 1 && InCircle(p4, x) == 1) {
cout << fixed << setprecision(10) << x.x << " ";
cout << fixed << setprecision(10) << x.y << "\n";
}
}
}
return 0;
}
10
题意
给一个平面图,问最少删掉多少条边使得平面图没有环。
思路
比赛的时候完全没有思路,后来在补题的时候才想明白。其实,最少删边形成的无环图其实就是求一个最大生成树,后来才意识到这个trick。。。
代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
typedef pair<int, int> PII;
struct edge {
int u, v, w;
bool operator<(edge& a)const {
return w > a.w;
}
};
vector<edge>v;
int p[N];
int n, m;
vector<int>ans;
int find(int num) {
if (p[num] == num) {
return num;
}
return p[num] = find(p[num]);
}
void kruskal() {
for (int i = 0; i < m; i++) {
if (find(v[i].u) != find(v[i].v)) {
p[find(v[i].u)] = find(v[i].v);
} else {
ans.push_back(v[i].w);
}
}
}
void solve() {
cin >> n >> m;
ans.clear();
v.clear();
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 1; i <= m; i++) {
edge x;
cin >> x.u >> x.v;
x.w = i;
v.push_back(x);
}
sort(v.begin(), v.end());
kruskal();
reverse(ans.begin(), ans.end());
cout << ans.size() << endl;
for (auto it : ans) cout << it << ' ';
cout << endl;
}
signed main() {
IOS;
int t = 1;
cin >> t;
for (int i = 1; i <= t; i++) {
solve();
}
}
12
题意
有k次操作,每次可以将一个数向后移动任意位置,求最大可以形成的数组
思路
贪心的思维,对于k比n大的时候,一定就是从大到小排序,否则,就是选择在前k个内最大的数将其前移,其他的数只要保持相对位置不变再执行归并操作就可以了。
代码
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
using namespace std;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int maxn = 1e6 + 5;
const double eps = 1e-9;
typedef pair<int, int> PII;
int a[N];
void solve() {
vector<int>st,v2;
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i <= n; i++) {
while (st.size() && a[i] > st.back() && k) {
k--;
v2.push_back(st.back());
st.pop_back();
}
st.push_back(a[i]);
}
sort(v2.begin(),v2.end(), greater<int>());
// while (st.size()) {
// v2.push_back(st.top());
// st.pop();
// }
// for (; i <= n; i++)v2.push_back(a[i]);
int p1=0,p2=0;
int cnt=1;
// for(auto it:st) cout<<it<<' ';
// cout<<endl;
// for(auto it:v2) cout<<it<<' ';
// cout<<endl;
while(cnt <= n) {
if(p1>=st.size()) {
cout<<v2[p2++]<<" \n"[cnt==n];
}
else if(p2>=v2.size()) {
cout<<st[p1++]<<" \n"[cnt==n];
}
else {
if(st[p1]>=v2[p2]) {
cout<<st[p1++]<<" \n"[cnt==n];
}
else {
cout<<v2[p2++]<<" \n"[cnt==n];
}
}
cnt++;
}
// cout<<endl;
}
signed main() {
IOS;
int T = 1;
cin >> T;
while (T--) {
solve();
}
}