『模拟赛』CSP-S模拟12
Rank
有点烂
A. 小 h 的几何
虽然但是看起来这就是签。赛时看到计算几何直接润了,没看到送的 20pts。
主要问题在证一个结论:九点圆圆心位于垂心和外心的中点。几何证法见此,用到的全是初中知识,很好懂。证完就很水了,圆心即为 \(\frac{A+B+C}{2}\),随便算个选中的方案数再乘上总概率就完了。系数是 \(\frac{(n-1)(n-2)}{2}\times \frac{6}{n(n-1)(n-2)}=\frac{3}{n}\)。复杂度线性。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 5e5 + 5, M = 5e5;
const int mod = 998244353;
const double pai = 3.1415926535897932384626;
int n;
double ansx, ansy;
namespace Wisadel
{
short main()
{
freopen("geometry.in", "r", stdin) , freopen("geometry.out", "w", stdout);
n = qr;
fo(i, 1, n)
{
double a; cin >> a;
a = (a * pai) / (1.0 * 1e9);
ansx += cos(a) * 3 / (2.0 * n);
ansy += sin(a) * 3 / (2.0 * n);
}
printf("%.11lf %.11lf\n", ansx, ansy);
return Ratio;
}
}
signed main(){return Wisadel::main();}
B. 小 w 的代数
一直以为这道是签,特殊性质狂挂,只有 20pts,寄。
正解果然是树形 dp,用到了圆方树优化,圆点统计方点转移。设 \(f_{i,j}\) 表示到点 \(i\) 链尾为 \(j\) 的方案数。发现在链上是好转移的,考虑怎么在环上转移。我们可以拆环成链,在这道题上体现就是顺逆时针分别考虑,二者只会在进入的点的答案上重复统计,其余由于顺序不同方案都是不交的。然后就做完了,复杂度是 \(\mathcal{O(n^3)}\) 的,不是很优但足够通过本题。
然后就是由这道题发现的小知识。Tarjan 求点双时,判断形成点双的条件写 low[v] >= dfn[u]
是一定对的,而如果判断条件写了取等,则一定不能判掉由父亲过来的边,即不能写 if(v == fa) continue;
。证明很好证,简单手模就出来了。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e5 + 5, M = 5e5;
const int mod = 998244353;
int n, m, tot;
int dfn[N], low[N], dt;
int hh[N], to[N << 1], ne[N << 1], cnt;
int f[1005][1005], g[N], s;
ll ans;
vector<int> e[N], zc;
stack<int> st;
namespace Wisadel
{
void Wadd(int u, int v)
{
to[++cnt] = v;
ne[cnt] = hh[u];
hh[u] = cnt;
}
void Wtarjan(int u, int fa)
{
dfn[u] = low[u] = ++dt, st.push(u);
for(int i = hh[u]; i != -1; i = ne[i])
{
int v = to[i];
if(v == fa) continue;
if(!dfn[v])
{
Wtarjan(v, u);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u])
{
tot++;
while(st.size())
{
int zc = st.top(); st.pop();
e[zc].P_B(tot), e[tot].P_B(zc);
if(zc == v) break;
}
e[u].P_B(tot), e[tot].P_B(u);
}
}
else low[u] = min(low[u], dfn[v]);
}
}
void Wdfs(int u, int fa)
{
if(u <= n)
{
fo(i, s, u - 1) ans = (ans + f[u][i]) % mod;
fo(i, s, u - 1) f[u][u] = (f[u][u] + f[u][i]) % mod;
}
else
{
int cz = 0, len = e[u].size();
fo(i, 0, len - 1) if(e[u][i] == fa){cz = i; break;}
zc.clear();
for(int i = (cz + 1) % len; i != cz; i = (i + 1) % len) zc.P_B(e[u][i]);
fo(i, s, n) g[i] = f[fa][i];
for(int v : zc)
{
fo(i, s, n) f[v][i] = (f[v][i] + g[i]) % mod;
fo(i, s, v - 1) g[v] = (g[v] + g[i]) % mod;
}
fo(i, s, n) g[i] = f[fa][i];
reverse(zc.begin(), zc.end());
for(int v : zc)
{
fo(i, s, n) f[v][i] = (f[v][i] + g[i]) % mod;
fo(i, s, v - 1) g[v] = (g[v] + g[i]) % mod;
}
for(int v : zc) fo(i, s, n)
f[v][i] = (f[v][i] - f[fa][i] + mod) % mod;
}
for(int v : e[u]) if(v != fa) Wdfs(v, u);
}
short main()
{
freopen("algebra.in", "r", stdin) , freopen("algebra.out", "w", stdout);
n = qr, m = qr;
memset(hh, -1, sizeof hh);
fo(i, 1, m)
{
int a = qr, b = qr;
Wadd(a, b), Wadd(b, a);
}
tot = n;
Wtarjan(1, 0);
fo(i, 1, n)
{
fo(j, 1, n) fo(k, 1, n) f[j][k] = 0;
f[i][i] = 1;
s = i;
Wdfs(i, i);
}
ans = (ans + n) % mod;
printf("%lld\n", ans);
return Ratio;
}
}
signed main(){return Wisadel::main();}
C. 小 y 的数论
nt 题面完全看不懂。据 xrlong 所说这是一道集合了诸多板子的题。
D. 小 j 的组合
真正的签。
考虑每次选择点相当于给这个点多一次经过机会,理解了这一点就很好办了。考虑每一个点最后都会回到首尾这一条链上,那么首尾链最长时可得加点次数最少。这又是一棵树,因此问题就变成了求树的直径。范围很小,直接 Floyd 求就行。然后 dfs 模拟跑一遍即可。不用 Floyd 复杂度大概是线性的,用了 \(\mathcal{O(n^3)}\),\(n\le 100\),影响不大。
点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch = getchar();lx x = 0 , f = 1;
for(;ch<'0'||ch>'9';ch = getchar()) if(ch == '-') f = -1;
for(;ch>= '0' && ch<= '9';ch = getchar()) x = (x<<3) + (x<<1) + (ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define pii pair<int, int>
#define M_P(a, b) make_pair(a, b)
#define fi first
#define se second
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 2e5 + 5, M = 5e5;
int n, tot;
int d[105][105];
int hh[N], to[N << 1], ne[N << 1], cnt;
bool yz[N];
vector<int> ans;
namespace Wisadel
{
void Wadd(int u, int v)
{
to[++cnt] = v;
ne[cnt] = hh[u];
hh[u] = cnt;
}
void Wdfs(int u, int tar)
{
int zc = 0;
yz[u] = 1; ans.P_B(u);
for(int i = hh[u]; i != -1; i = ne[i])
{
int v = to[i];
if(yz[v]) continue;
if(d[tar][v] + 1 == d[tar][u])
{
zc = v;
continue;
}
Wdfs(v, tar);
printf("%d ", u);
ans.P_B(++tot);
}
if(zc) Wdfs(zc, tar);
}
short main()
{
freopen("combo.in", "r", stdin) , freopen("combo.out", "w", stdout);
n = qr;
memset(hh, -1, sizeof hh);
fo(i, 1, n) fo(j, i + 1, n) d[i][j] = d[j][i] = 1e9;
fo(i, 1, n - 1)
{
int a = qr, b = qr;
d[a][b] = d[b][a] = 1;
Wadd(a, b), Wadd(b, a);
}
tot = n;
fo(k, 1, n) fo(i, 1, n) fo(j, 1, n)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
int st = 1, ed = 1;
fo(i, 1, n) fo(j, i + 1, n) if(d[i][j] > d[st][ed]) st = i, ed = j;
printf("%d\n", n - d[st][ed] - 1);
Wdfs(st, ed); puts("");
for(int i : ans) printf("%d ", i);puts("");
return Ratio;
}
}
signed main(){return Wisadel::main();}
末
感觉一天打的好一天打得烂?然后中午和 CTH 浅算一下发现 CSP 和 NOIP 都是烂的那天?
CTH:你停一天不就行了。
感觉非联考的题好有水平啊,每次都有几个挺毒瘤的。
起码学了学圆方树,不知道九点圆等到回归 whk 后有没有机会用,不过学了总是好的。
明后天据说有 \(n\) 场比赛要打,模拟赛,ATCoder,CF,STAOI。。。到时候看改题情况决定打不打吧。
完结撒花!
艾雅法拉~