杭电多校第六场个人补题6 7 9 10 12

杭电多校第六场个人补题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 atimodp个点,对于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();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值