2021"MINIEYE杯"中超(7~10)补题

2021"MINIEYE杯"中超(7)

1003 Fall with Trees

场上t了,代码如下:

tle code
#include <cstdio>

using namespace std;

int t;
int k;
double xr, yr, xls, yls, xrs, yrs;

void solve()
{
    scanf("%d", &k);
    scanf("%lf%lf%lf%lf%lf%lf", &xr, &yr, &xls, &yls, &xrs, &yrs);
    double t = xrs - xls;
    double h = yr - yrs;
    double u = 0, v = t;
    double ans = 0;
    for (int i = 2; i <= k; i ++ )
    {
        ans += (u + v) * h / 2;
        u = v;
        v += t / 2;
        t /= 2;
    }
    
    printf("%.3f
", ans);
}

int main()
{
    scanf("%d", &t);
    while (t -- ) solve();
    return 0;
} 

推公式:设初始width = d,那么w_i = 2 * d * (1 - 2^(-i))

对于每一层的梯形面积:S_i = h / 2 * (w_i + w_i+1)。

那么答案即为对S_i求和。推出来后等比数列求和得到:

ans = d * h / 2.0 * (4.0 * (k - 1) - 3.0 * (2.0 - pow(2,2 - k)))

#include <bits/stdc++.h>

using namespace std;

int t;
int k;
double xr, yr, xls, yls, xrs, yrs;

void solve()
{
    scanf("%d", &k);
    scanf("%lf%lf%lf%lf%lf%lf", &xr, &yr, &xls, &yls, &xrs, &yrs);
    double d = xrs - xls; double h = yr - yls;
    double ans = d * h / 2.0 * (4.0 * (k - 1) - 3.0 * (2.0 - pow(2,2 - k)));
    printf("%.3f
", ans);
}

int main()
{
    scanf("%d", &t);
    while (t -- ) solve();
    return 0;
} 

比赛时思路正确了,即先建图然后遍历各个环,求每个环的平均值。但是在计算平均值时计算成了连通块的点权均值,导致错误。每个点可能在跳若干次才进环,所以只需要统计各个环内的点权均值。

我们可以拓扑排序消除非环点,然后跑一遍拓扑后统计各个环的点权均值。

#include <bits/stdc++.h>

typedef long long ll;

const int N = 100010;

int n,a[N], din[N];

void solve()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) din[i] = 0;//记录各个点的入度
	for(int i=1;i<=n;i++) scanf("%d",&a[i]), din[a[i]]++;
	std::queue<int> Q;
	for(int i=1;i<=n;i++) if(din[i] == 0) Q.push(i);//拓扑排序
	while(!Q.empty())
    {
		int u = Q.front();
		Q.pop();
		din[a[u]]--;
		if(din[a[u]] == 0) Q.push(a[u]);
	}
	ll p=-1,q=-1;
	for(int i=1;i<=n;i++)
    {
		if(din[i]==0) continue;//如果访问到了非环点,跳过
		ll tp=0,tq=0;
		for(;din[i];i=a[i])//遍历环
        {
			tp += i;
			tq++;
			din[i] = 0;//遍历过此点,标记入度为0
		}
		if(p == -1) p = tp, q = tq;//第一个环
        else
        {
			if(p * tq != q * tp) {puts("NO"); return;}
		}
	}
	puts("YES");
	return;
}

int main()
{
	int T;
	scanf("%d",&T);
	while(T--) solve();
}

1008 Smzzl with Greedy Snake
1012 Yiwen with Sqc

2021"MINIEYE杯"中超(8)

1003 Ink on paper

类似综合训练2中的一题,最小生成树问题,点数较少,我们预处理出每两个点之间的距离,然后跑一遍prim算法即可。

int n, m;
int g[N][N], dist[N];
//邻接矩阵存储所有边
//dist存储其他点到S的距离
bool st[N];
int x[N], y[N];
int get_(int a,int b) 
{
    return (x[a] - x[b]) * (x[a] - x[b]) + (y[a] - y[b]) * (y[a] - y[b]);
}

int prim() 
{
    memset(dist, INF, sizeof dist);
    int res = 0;
    memset(st,0,sizeof st);
    for(int i = 0; i < n; i++) 
    {
        int t = -1;
        for(int j = 1; j <= n; j++) 
            if(!st[j] && (t == -1 || dist[t] > dist[j]))
                t = j;
        //寻找离集合S最近的点        
        if(i && dist[t] == INF) return INF;
        //判断是否连通,有无最小生成树
        if(i) res = max(dist[t], res);
        st[t] = true;
        //更新最新S的权值和
        for(int j = 1; j <= n; j++) dist[j] = min(dist[j], g[t][j]);
    }
    return res;
}

void solve() 
{
    cin >> n;
    int u, v, w;
    for(int i = 1;i <= n;i ++) cin >> x[i] >> y[i];
    for(int i = 1; i <= n; i++)
        for(int j = i + 1; j <= n; j++) g[i][j] = g[j][i] = get_(i,j);
    int t = prim();
    cout << t << endl;
}
1006 GCD Game

一个数字最多可以gcd它的质因子的次数之和次,然后就转化成了nim石子游戏,n堆石子,每次选择可以拿 1~f(ai)个。结论:所有次数异或不等于0先手胜。

int primes[M], tot;
int cnt[M];
bool st[M];

void init()
{
    for(int i = 2;i < M;i ++)
    {
        if(!st[i])
        {
            primes[++ tot] = i;
            cnt[i] = 1;
        }
        for(int j = 1; j <= tot && primes[j] * i < M;j ++)
        {
            cnt[i * primes[j]] = cnt[i] + 1;
            st[i * primes[j]] = 1;
            if(i % primes[j] == 0) break;
        }
    }
}

void solve()
{
    int n;
    cin >> n;
    int ans = 0, x;
    for(int i = 1;i <= n;i ++) cin >> x, ans ^= cnt[x];
    if(ans == 0) cout << "Bob" << endl;
    else cout << "Alice" << endl;
}

2021"MINIEYE杯"中超(10)

1003 Pty loves lines

所有直线都不平行的时候,每条边和其他边都有交点,最多有n * (n - 1) / 2个交点。

接着考虑n - 1条直线平行,有 1 * (n - 1)

n - 2条直线平行,另外两条可以平行可以相交,有2 * (n - 2) + 0或者2 * (n - 2) + 1

n - 3条直线平行,另外三条可以三条都平行,三条都相交,有两条平行,有3 * (n - 3) + 0 或者+ 2 或者 + 3

定义f[i, j]表示i条直线,j个交点是否是可以凑出来的,是个bool值。f[i, j] = f[i - k, j + k * (i - k)] 然后可以bitset优化。

const int N = 710, M = 32000;

bitset<M> f[N];

void init() 
{
    f[0][0] = 1;
    for (int i = 1; i <= 700; i ++ ) for (int k = 1; k <= i; k ++ ) f[i] |= f[i - k] << (k * (i - k));
}

void solve()
{
    int n;
    cin >> n;
    int limit = min(M - 1, n * (n - 1) / 2);
    bool flag = 0;
    for(int i = 0;i <= limit;i ++)
    {
        if(f[n][i])
        {
            if(flag) cout << ' ';
            else flag = 1; 
            cout << i;
        } 
    }  
    for(int i = limit + 1;i <= (n * (n - 1) / 2);i ++) cout << ' ' << i; cout << endl;
}
原文地址:https://www.cnblogs.com/scl0725/p/15184478.html