2021年度训练联盟热身训练赛第一场 部分题解(待补)

比赛链接:https://ac.nowcoder.com/acm/contest/12606#question

A Weird Flecks, But OK

队友写的,求最小外接圆直径

/*Siberian Squirrel*/
/*Cute JinFish*/
#include<bits/stdc++.h>

#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
//#define ACM_LOCAL

using namespace std;
typedef long long ll;

const double PI = acos(-1);
const double eps = 1e-4;
/*const int MOD = 998244353, r = 119, k = 23, g = 3;
const int MOD = 1004535809, r = 479, k = 21, g = 3;*/
const int MOD = 1e9 + 7;
const int M = 1e7 + 10;
const int N = 4e5 + 10;

int dcmp(double x) {
	if(fabs(x) < eps) return 0;
	else return x < 0? -1: 1;
}
//inline int rnd(){static int seed=2333;return seed=(((seed*666666ll+20050818)%998244353)^1000000007)%1004535809;}

int n;
struct nodee {
	double x, y, z;
} _p[N];
struct node {
	double x, y;
} p[N];

node c; ///圆心
double r;   ///半径

int sgn(double x) {
	if (fabs(x) < eps)
		return 0;
	else
		return x < 0 ? -1 : 1;
}

double Distance(node A, node B) { ///两点距离
	return hypot(A.x - B.x, A.y - B.y); ///hypot(a, b)求以a, b为直角边的直角三角形斜边长
}

///求三角形abc的外接圆圆心
node circle_center(const node a, const node b, const node c) {
	node center;
	double a1 = b.x - a.x, b1 = b.y - a.y, c1 = (a1 * a1 + b1 * b1) / 2;
	double a2 = c.x - a.x, b2 = c.y - a.y, c2 = (a2 * a2 + b2 * b2) / 2;
	double d = a1 * b2 - a2 * b1;
	center.x = a.x + (c1 * b2 - c2 * b1) / d;
	center.y = a.y + (a1 * c2 - a2 * c1) / d;
	return center;
}

///求最小圆覆盖,返回圆心c和半径r:
void min_cover_circle(int n) {
	random_shuffle(p, p + n);             ///打乱所有点
	c = p[0];
	r = 0;                    ///第一个点
	for (int i = 1; i < n; ++i) {      ///剩下所有点
		if (sgn(Distance(p[i], c) - r) > 0) { ///pi在圆外部
			c = p[i];
			r = 0;                ///将圆心设为pi半径为0
			for (int j = 0; j < i; ++j) { ///重新检查前面的点
				if (sgn(Distance(p[j], c) - r) > 0) { ///两点定圆
					c.x = (p[i].x + p[j].x) / 2;
					c.y = (p[i].y + p[j].y) / 2;
					r = Distance(p[j], c);
					for (int k = 0; k < j; ++k) {
						if (sgn(Distance(p[k], c) - r) > 0) {
							c = circle_center(p[i], p[j], p[k]);
							r = Distance(p[i], c);
						}
					}
				}
			}
		}
	}
}

inline void solve(ll res = 0) {
	double minn = 1.0 * INT_MAX;
	for(int i = 0; i < n; ++ i) {
		p[i].x = _p[i].x;
		p[i].y = _p[i].y;
	}
	min_cover_circle(n);
//	cout << "1:" << setprecision(10) << r * 2 << endl;
	minn = min(minn, 2.0 * r);
	for(int i = 0; i < n; ++ i) {
		p[i].x = _p[i].x;
		p[i].y = _p[i].z;
	}
	min_cover_circle(n);
//	cout << "2:" << setprecision(10) << r * 2 << endl;
	minn = min(minn, 2.0 * r);
	for(int i = 0; i < n; ++ i) {
		p[i].x = _p[i].z;
		p[i].y = _p[i].y;
	}
	min_cover_circle(n);
//	cout << "3:" << setprecision(10) << r * 2 << endl;
	minn = min(minn, 2.0 * r);
	cout << setprecision(10) << minn << endl;
}


int main() {
	IO;
#ifdef ACM_LOCAL
	freopen("input", "r", stdin);
	freopen("output", "w", stdout);
#endif
	int o = 1;
//	cin >> o;
	while(o --) {
		cin >> n;
		for(int i = 0; i < n; ++ i) {
			cin >> _p[i].x >> _p[i].y >> _p[i].z;
		}
		solve();
	}
	return 0;
}

B Code Names

一开始觉得是二分图,然后搞了半天没有想到构造二分图的方法 ,浪费了1个多小时在这个上面还是挺傻逼的,稍加思考其实就是个带花树的裸题而已,不懂带花树的搜一下一般图的最大匹配,然后这题就是个最大独立集也就是n-最大匹配数。

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
int n;
string s[N];
char ai[N], bi[N];
int m,cnt,last[N],ty[N],tic[N],tim,f[N],match[N],pre[N];
struct edge{int to,next;}e[300005];
queue<int> que;

int read()
{
    int x=0,f=1;char ch=getchar();
    while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

void addedge(int u,int v)
{
    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;
}

int find(int x)
{
    if (f[x]==x) return x;
    else return f[x]=find(f[x]);
}

int lca(int x,int y)
{
    for (tim++;;swap(x,y))
        if (x)
        {
            x=find(x);
            if (tic[x]==tim) return x;
            tic[x]=tim;x=pre[match[x]];
        }
}

void shrink(int x,int y,int p)
{
    while (find(x)!=p)
    {
        pre[x]=y;y=match[x];
        if (ty[y]==2) ty[y]=1,que.push(y);
        if (find(x)==x) f[x]=p;
        if (find(y)==y) f[y]=p;
        x=pre[y];
    }
}

bool aug(int s)
{
    for (int i=1;i<=n;i++) f[i]=i,ty[i]=pre[i]=0;
    while (!que.empty()) que.pop();
    que.push(s);ty[s]=1;
    while (!que.empty())
    {
        int x=que.front();que.pop();
        for (int i=last[x],y=e[i].to;i;i=e[i].next,y=e[i].to)
        {
            if (find(x)==find(y)||ty[y]==2) continue;
            if (!ty[y])
            {
                ty[y]=2;pre[y]=x;
                if (!match[y])
                {
                    for (int tmp;y;y=tmp,x=pre[y])
                        tmp=match[x],match[x]=y,match[y]=x;
                    return 1;
                }
                else ty[match[y]]=1,que.push(match[y]);
            }
            else if (ty[y]==1)
            {
                int p=lca(x,y);
                shrink(x,y,p);
                shrink(y,x,p);
            }
        }
    }
    return 0;
}

void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> s[i];
    for (int i = 1; i <= n; i++) {
        for (int j = i+1; j <= n; j++) {
            int num = 0;
            for (int k = 0; k < s[i].size(); k++) {
                if (s[i][k] != s[j][k]) {
                    num++;
                    if (num <= 2) ai[num] = s[i][k], bi[num] = s[j][k];
                }
            }
            if (num == 2 && ai[1] == bi[2] && ai[2] == bi[1]) addedge(i, j);
        }
    }
    int ans = 0;
    for (int i = 1; i <= n; i++) {
        if (!match[i] && aug(i)) ans++;
    }
    cout << n - ans << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

D Some Sum

队友写的签到题

/*Siberian Squirrel*/
/*Cute JinFish*/
#include<bits/stdc++.h>

#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
//#define ACM_LOCAL

using namespace std;
typedef long long ll;

const double PI = acos(-1);
const double eps = 1e-6;
/*const int MOD = 998244353, r = 119, k = 23, g = 3;
const int MOD = 1004535809, r = 479, k = 21, g = 3;*/
const int MOD = 1e9 + 7;
const int M = 1e7 + 10;
const int N = 4e5 + 10;

int dcmp(double x) {
	if(fabs(x) < eps) return 0;
	else return x < 0? -1: 1;
}
//inline int rnd(){static int seed=2333;return seed=(((seed*666666ll+20050818)%998244353)^1000000007)%1004535809;}

int n; 

inline void solve(ll res = 0) {
	if(n & 1) cout << "Either" << endl;
	else if((n / 2) % 2 == 0) cout << "Even" << endl;
	else cout << "Odd" << endl;
}


int main() {
	IO;
#ifdef ACM_LOCAL
	freopen("input", "r", stdin);
	freopen("output", "w", stdout);
#endif
	int o = 1;
//	cin >> o;
	while(o --) {
		cin >> n;	
		solve();
	}
	return 0;
}

E Early Orders

因为取牌是有后效性的,也就是说你要提前处理出所有数值的牌还剩多少张,然后就是用单调栈进行贪心了。我们要维护单调栈内递增,这样可以做到当前最优的状态,然后配合预处理的牌的张数进行出栈。有一个地方要特殊注意一下,如果这个数值已经在栈内了,那就直接过。

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
int a[N], cnt[N];
int stk[N], tp, vis[N];
void solve() {
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i++) cin >> a[i], cnt[a[i]]++;
    for (int i = 1; i <= n; i++) {
        if (!vis[a[i]]) {
            while (tp && a[stk[tp]] > a[i] && cnt[a[stk[tp]]]) {
                vis[a[stk[tp]]] = 0;
                tp--;
            }
            stk[++tp] = i;
            vis[a[i]] = 1;
        }
        //for (int j = 1; j <= tp; j++) cout << a[stk[j]] << " ";
        //cout << endl;
        cnt[a[i]]--;
    }
    for (int i = 1; i <= tp; i++) cout << a[stk[i]] << " ";
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

F Pulling Their Weight

数值很小,直接处理前缀和后缀和,枚举每个数就可以了,简单签到题

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
const int N = 1e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
int n, m, a[N];
ll pre[N], back[N], cnt[N];
void solve() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i], cnt[a[i]]++;
    for (int i = 1; i <= 1e5; i++) pre[i] = pre[i-1] + cnt[i] * i;
    for (int i = 1e5; i >= 1; i--) back[i] = back[i+1] + cnt[i] * i;
    for (int i = 1; i <= 1e5; i++) {
        if (pre[i-1] == back[i+1]) {
            printf("%d\n", i);
            return;
        }
    }
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

H On Average They’re Purple

题目花里胡哨,其实就是一个bfs(最短路-1也可以)

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
struct Edge {
    int to, next, w;
}e[M];
int h[N], cnt, vis[N], dis[N];
void add(int u, int v) {
    e[cnt].to = v;
    e[cnt].next = h[u];
    h[u] = cnt++;
}
void bfs(int s) {
    queue<int> que;
    memset(dis, 0x3f, sizeof dis);
    for (int i = h[s]; ~i; i = e[i].next) dis[e[i].to] = 0, que.push(e[i].to);
    vis[s] = 1; dis[s] = 0;
    while (que.size()) {
        int now = que.front();
        que.pop();
        vis[now] = 1;
        for (int i = h[now]; ~i; i = e[i].next) {
            int v = e[i].to;
            dis[v] = min(dis[v], dis[now] + 1);
            if (!vis[v]) que.push(v);
        }
    }
}
void solve() {
    int n, m; cin >> n >> m;
    memset(h, -1, sizeof h);
    for (int i = 1; i <= m; i++) {
        int u, v; cin >> u >> v;
        add(u, v); add(v, u);
    }
    bfs(1);
    cout << dis[n] << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

I Full Depth Morning Show

树形dp,需要预处理一些东西
T代表子树节点权值和
siz代表子树子节点个数
dist代表所有子节点到当前节点的距离和
disT代表所有子节点到当前节点距离*子节点的和
然后就可以开始转移了
根转移写得少,代码略丑

#include <bits/stdc++.h>
using namespace std;
//#define ACM_LOCAL
#define re register
#define fi first
#define se second
const int N = 3e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
ll T[N], dist[N], disT[N], val[N], siz[N], ans[N];
int cnt, h[N], n, m;
struct Edge {
    int to, next, w;
}e[M];
void add(int u, int v, int w) {
    e[cnt].to = v;
    e[cnt].w = w;
    e[cnt].next = h[u];
    h[u] = cnt++;
}

void dfs1(int u, int fa) {
    siz[u] = 1; T[u] = val[u];
    for (int i = h[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if (v == fa) continue;
        dfs1(v, u);
        siz[u] += siz[v];
        T[u] += T[v];
        dist[u] += siz[v] * e[i].w + dist[v];
        disT[u] += e[i].w * T[v] + disT[v];
    }
}
void dfs2(int u, int fa) {
    for (int i = h[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if (v == fa) continue;
        dist[v] += dist[u] - dist[v] - e[i].w * siz[v] + (siz[u] - siz[v]) * e[i].w;
        disT[v] += disT[u] - disT[v] - e[i].w * T[v] + (T[u] - T[v]) * e[i].w;
        ans[v] = val[v] * dist[v] + disT[v];
        siz[v] = siz[u];
        T[v] = T[u];
        dfs2(v, u);
    }
}
void solve() {
    cin >> n;
    memset(h, -1, sizeof h);
    for (int i = 1; i <= n; i++) cin >> val[i];
    for (int i = 1; i <= n-1; i++) {
        int u, v, w; cin >> u >> v >> w;
        add(u, v, w), add(v, u, w);
    }
    dfs1(1, 0);
    ans[1] = disT[1] + dist[1] * val[1];
    dfs2(1, 0);
    for (int i = 1; i <= n; i++) printf("%lld\n", ans[i]);
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}

J This Ain’t Your Grandpa’s Checkerboard

签到题

#include <bits/stdc++.h>
using namespace std;
#define re register
#define fi first
#define se second
const int N = 2e5 + 10;
const int M = 1e6 + 10;
const int INF = 0x3f3f3f3f;
const double eps = 1e-4;
const int MOD = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> PII;
int mp[100][100];
void solve() {
    int n; cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            char c; cin >> c;
            if (c == 'W') mp[i][j] = 0;
            else mp[i][j] = 1;
        }
    }
    int f = 0;
    for (int i = 1; i <= n; i++) {
        int black = 0, white = 0;
        for (int j = 1; j <= n; j++) {
            if (mp[i][j] == 0) white++;
            else black++;
        }
        if (white != black) f = 1;
    }
    for (int i = 1; i <= n; i++) {
        int black = 0, white = 0;
        for (int j = 1; j <= n; j++) {
            if (mp[j][i] == 0) white++;
            else black++;
        }
        if (white != black) f = 1;
    }
    for (int i = 1; i <= n; i++) {
        int tmp = 1;
        for (int j = 2; j <= n; j++) {
            if (mp[i][j] == mp[i][j-1]) tmp++;
            else tmp = 1;
            if (tmp >= 3) f = 1;
        }
    }
    for (int i = 1; i <= n; i++) {
        int tmp = 1;
        for (int j = 2; j <= n; j++) {
            if (mp[j][i] == mp[j-1][i]) tmp++;
            else tmp = 1;
            if (tmp >= 3) f = 1;
        }
    }
    if (f) cout << 0 << endl;
    else cout << 1 << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
#ifdef ACM_LOCAL
    freopen("input", "r", stdin);
    freopen("output", "w", stdout);
#endif
    solve();
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值