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\n", 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\n", ans);
}
int main()
{
scanf("%d", &t);
while (t -- ) solve();
return 0;
}
1007 Link with Limit
比赛时思路正确了,即先建图然后遍历各个环,求每个环的平均值。但是在计算平均值时计算成了连通块的点权均值,导致错误。每个点可能在跳若干次才进环,所以只需要统计各个环内的点权均值。
我们可以拓扑排序消除非环点,然后跑一遍拓扑后统计各个环的点权均值。
#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;
}