2022NOIPA层联测11
整场考试都被我拿来死磕T3了,以为它是树形dp,结果没开long long连暴力的15都没拿到。。听说考前爆0可以涨rp,不知道是不是真的。。
In the dark days, do not let the cold fate of secretly pleased; fate since to abuse us, we should use the attitude of retaliation.
– Shakespeare
在灰暗的日子中,不要让冷酷的命运窃喜;命运既然来凌辱我们,我们就应该用处之泰然的态度予以报复。
– 莎士比亚
A. 小 h 的几何
“熟知”九点圆圆心是外心O和垂心H的中点……我连九点圆是什么都没听说过……那个向量公式大概学过:
然后正弦和余弦都是库函数,对于每种情况不用枚举i,j,k,求一下和记录贡献的次数就好,固定一个剩下的任选就是C(n-1, 2),这东西cr好像给我讲过一次,我又听她讲了一遍。。
code
#include <bits/stdc++.h>
using namespace std;
typedef long double ll;
const int maxn = 5e5 + 3;
const ll B = 1e9, PI = 3.1415926535;
int n, p[maxn];
ll ls[maxn], rs[maxn], sx, sy;
inline 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 << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int main()
{
freopen("geometry.in", "r", stdin);
freopen("geometry.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
int q = read();
ls[i] = cos((ll)q/B*PI); rs[i] = sin((ll)q/B*PI);
}
for(int i=1; i<=n; i++)
{
sx += ls[i]; sy += rs[i];
}
printf("%.15Lf %.15Lf\n", sx*1.5/n, sy*1.5/n);
return 0;
}
B. 小w 的代数
子链概念里的那个路径包含就可以不是只能包含,审对题之后发现连暴力都不会了。。
%%%%%351238 以下代码是鹤的 部分分55:链条树:除了空集什么都能选;菊花树:最多只有两个点能被同时选上,要求大小关系就可以写成等差数列求和的形式;小数据:带撤销形式回溯的dfs,hash一下重复情况;普通的树:用树形dp的形式累计一下答案的个数。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 555;
const int mod = 998244353;
const ull B = 233;
int n, m, top, fa[maxn], v[maxn], dd[maxn], stk[maxn];
ll ans, f[maxn];
ull hs[maxn];
unordered_map<ull, bool> mp;
inline 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 << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
ll qpow(ll a, ll b)
{
ll ans = 1;
while(b)
{
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans;
}
struct node
{
int next, to;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y)
{
a[++len].to = y; a[len].next = head[x];
head[x] = len;
}
void dfs(int x, int dad)
{
for(int i=head[x]; i; i=a[i].next)
{
int kid = a[i].to;
if(kid == dad) continue;
fa[kid] = x;
dfs(kid, x);
}
}
void dfss(int x, int dad)
{
f[x] = 1; dd[x] = dad;
for(int i=head[x]; i; i=a[i].next)
{
int kid = a[i].to;
if(kid == dad) continue;
dfss(kid, x);
}
}
void work(int x, int dad)
{
for(int i=head[x]; i; i=a[i].next)
{
int kid = a[i].to;
if(kid == dad) continue;
work(kid, x);
}
int now = dd[x];
while(now)
{
if(x > now) {f[now] += f[x]; f[now] %= mod;}
now = dd[now];
}
}
void dfs2(int x, int dad)
{
if(!mp[hs[top]]) mp[hs[top]] = 1, ans = ans+1>=mod ? ans+1-mod : ans+1;
v[x] = 1;
for(int i=head[x]; i; i=a[i].next)
{
int kid = a[i].to;
if(v[kid]) continue;
if(kid > stk[top] && !v[kid])
{
ull h = hs[top];
stk[++top] = kid;
hs[top] = hs[top-1]*B+kid;
dfs2(kid, x);
hs[--top] = h;
}
dfs2(kid, x);
}
v[x] = 0;
}
int main()
{
freopen("algebra.in", "r", stdin);
freopen("algebra.out", "w", stdout);
n = read(); m = read();
for(int i=1; i<=m; i++)
{
int x = read(), y = read();
add(x, y); add(y, x);
}
if(m == n-1)
{
dfs(1, 0);
int sp1 = 0, sp2 = 0;
for(int i=2; i<=n; i++)
{
if(fa[i] != i-1) sp1 = 1;
if(fa[i] != 1) sp2 = 1;
}
if(!sp1) {printf("%lld\n", qpow(2,n)-1); exit(0);}
if(!sp2) {printf("%lld\n", (1ll*n*n%mod+n)%mod*qpow(2,mod-2)%mod); exit(0);}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++) f[j] = 0;
dfss(i, 0);
work(i, 0);
ans += f[i]; while(ans >= mod) ans -= mod;
}
printf("%lld\n", ans);
}
if(n <= 50)
{
for(int i=1; i<=n; i++)
{
hs[1] = i;
top = 0; stk[++top] = i;
dfs2(i, 0);
}
printf("%lld\n", ans);
}
return 0;
}
C. 小y 的数论
对于这么一个鬼畜,我是怎么以为它很水的!?是因为眼熟的斯坦纳树吗……
TLE 15
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 3;
int Max, q, l, r, n, k;
int dep[maxn], fa[maxn], siz[maxn], top[maxn], son[maxn];
ll val[maxn], ans;
bool vis[maxn];
vector<int> ext;
inline 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 << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to, w;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y, int w)
{
a[++len].to = y; a[len].next = head[x]; a[len].w = w;
head[x] = len;
}
int count(int x)
{
int res = 0;
while(x)
{
x -= (x & -x);
res++;
}
return res;
}
void find_heavy_edge(int u, int fat, int depth)
{
siz[u] = 1;
dep[u] = depth;
fa[u] = fat;
son[u] = 0;
int maxsize = 0;
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(dep[v]) continue;
find_heavy_edge(v, u, depth+1);
siz[u] += siz[v];
if(siz[v] > maxsize)
{
maxsize = siz[v];
son[u] = v;
}
}
}
void connect_heavy_edge(int u, int ancestor)
{
top[u] = ancestor;
if(son[u])
{
connect_heavy_edge(son[u], ancestor);
}
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa[u] || v == son[u]) continue;
connect_heavy_edge(v, v);
}
}
int LCA(int x, int y)
{
while(top[x] != top[y])
{
if(dep[top[x]] < dep[top[y]]) swap(x, y);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
return x;
}
void dfs(int u, int fa, int w)
{
if(vis[u]) val[u] = w;
else val[u] = 0;
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
dfs(v, u, a[i].w);
val[u] += val[v];
}
if(!vis[u] && val[u]) val[u] += w;
//printf("val[%d] = %d\n", u, val[u]);
}
void calc(int num)
{
//printf("New Case %d\n", num);
for(int i=l; i<=r; i++) vis[i] = 0;
ext.clear();
for(int i=1; i<=r-l+1; i++)
{
if(num&(1<<i-1)) vis[l+i-1] = 1, ext.push_back(l+i-1);
}
//for(int i=1; i<=n; i++) printf("%d ", vis[i]);
//printf("\n");
int lca = LCA(ext[0], ext[1]);
for(int i=2; i<ext.size(); i++)
{
lca = LCA(lca, ext[i]);
}
dfs(lca, fa[lca], 0);
ans = max(ans, val[lca]);
}
ll dfs2(int u, int fa)
{
ll sum1 = 0, sum2 = 0;
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
if((l <= v && v <= r) || vis[v])
{
sum2 = max(sum2, dfs2(v, u)+a[i].w);
vis[u] = 1;
if(sum2 > sum1) swap(sum2, sum1);
}
}
printf("sum1 = %lld sum2 = %lld\n", sum1, sum2);
ans = max(ans, sum1 + sum2);
return sum1;
}
void dfs2(int u, int fa, ll depth)
{
if(l <= u && u <= r) ans = max(ans, depth);
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
dfs2(v, u, depth+a[i].w);
}
}
void solve2()
{
//dfs2(1, 0);
//printf("%lld\n", ans);
for(int i=l; i<=r; i++)
{
dfs2(i, 0, 0);
}
printf("%lld\n", ans);
}
int main()
{
//freopen("1.in", "r", stdin);
freopen("number.in", "r", stdin);
freopen("number.out", "w", stdout);
n = read();
for(int i=1; i<n; i++)
{
int x = read(), y = read(), w = read();
add(x, y, w); add(y, x, w);
}
find_heavy_edge(1, 1, 1);
connect_heavy_edge(1, 1);
q = read();
while(q--)
{
l = read(), r = read(), k = read();
if(k == 1)
{
printf("0\n"); continue;
}
if(k == 2)
{
ans = 0; solve2(); continue;
}
for(int i=1; i<=n; i++) vis[i] = 0;
Max = 1 << (r-l+1); ans = 0;
for(int i=0; i<Max; i++)
{
if(count(i) != k) continue;
calc(i);
}
printf("%lld\n", ans);
}
return 0;
}
D. 小j 的组合
注意事项是操作编号和结果序列要求一一对应,不能根据度数预处理。。就这我赛时没切了它就很离谱
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 103;
int n, ans, d[maxn], cnt, nct[maxn];
vector<int> v1, v2, v3;
bool vis[maxn];
inline 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 << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y)
{
a[++len].to = y; a[len].next = head[x];
head[x] = len;
}
void update(int depth)
{
ans = depth;
v1.clear();
for(int i=1; i<=depth; i++)
{
v1.push_back(d[i]);
}
}
void dfs(int u, int fa, int depth)
{
d[depth] = u;
int son = 0;
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
dfs(v, u, depth+1);
son++;
}
if(son == 0 && depth > ans) update(depth);
}
void dfs2(int u, int fa)
{
v3.push_back(u);
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa || v == nct[u]) continue;
dfs2(v, u);
v3.push_back(++cnt);
v2.push_back(u);
}
if(nct[u])
{
dfs2(nct[u], u);
}
}
int main()
{
freopen("combo.in", "r", stdin);
freopen("combo.out", "w", stdout);
n = read();
for(int i=1; i<n; i++)
{
int x = read(), y = read();
add(x, y); add(y, x);
}
for(int i=1; i<=n; i++)
{
dfs(i, i, 1);
}
int sz = v1.size(); cnt = n;
for(int x : v1) vis[x] = 1;
for(int i=0; i<sz-1; i++)
{
nct[v1[i]] = v1[i+1];
}
dfs2(v1[0], 0);
int sz2 = v2.size();
printf("%d\n", sz2);
for(int i=0; i<sz2; i++)
{
printf("%d ", v2[i]);
}
printf("\n");
for(int x : v3)
{
printf("%d ", x);
}
return 0;
}
时光花火,水月星辰