感觉再这么成天咕下去不太好……
A. 天平
没有观察到只需要使得选出的砝码质量的gcd与所有砝码的fcd相等即可,但是发现应该让选出的砝码的gcd取到最小值。
我想找到最小的gcd选组成它们的两个数作为起点,以为最小值一定是其中之一,就这么省了个循环但是这个结论是错的所以WA 了,剩下的由【放进去】的假贪心想到每一轮找出一个能使gcd变到最小的选上。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 54, inf = 0x3f3f3f3f;
int n, a[maxn], step, mi=inf, id;
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;
}
bool check()
{
for(int i=1; i<=n; i++)
{
if(a[i] % mi) return false;
}
return true;
}
inline int gcd(int a, int b)
{
while(b^=a^=b^=a%=b);
return a;
}
int main()
{
freopen("weights.in", "r", stdin);
freopen("weights.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
a[i] = read();
if(a[i] < mi) mi = a[i], id = i;
}
if(check()) {printf("1\n"); exit(0);}
int las = mi;
/*vis[id] = 1; id = 0;
int las = mi;
for(int i=1; i<=n; i++)
{
if(vis[id]) continue;
int gd = gcd(a[i], las);
if(gd < mi) {mi = gd; id = i;}
}*/
int m1 = 0, m2 = 0;
for(int i=1; i<=n; i++)
{
for(int j=i+1; j<=n; j++)
{
int gd = gcd(a[i], a[j]);
if(gd < mi) {mi = gd, m1 = i, m2 = j;}
}
}
step = 2; vis[m1] = 1, vis[m2] = 1; id = 0;
if(check()) {printf("2\n"); exit(0);}
while(step <= n)
{
las = mi;
for(int i=1; i<=n; i++)
{
if(vis[i]) continue;
int gd = gcd(a[i], las);
if(gd < mi) {mi = gd; id = i;}
}
if(!id) {printf("%d\n", step); break;}
step++; vis[id] = 1; id = 0;
}
return 0;
}
B. 支配数据
把序列分成k段让每个序列相互独立线段树及时清空,一开始想把问题拆分:
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 2, inf = 0x3f3f3f3f;
const int maxQ = 1e7 + 4;
int n, a[maxn], k, Q, ans[maxn], cnt;
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 seg
{
struct node
{
int v, tag;
}t[maxn<<2];
void pushup(int x)
{
t[x].v = min(t[x<<1].v, t[x<<1|1].v);
}
void build(int x, int l, int r)
{
t[x].tag = 0;
if(l == r)
{
t[x].v = a[l]; return;
}
int mid = (l + r) >> 1;
build(x<<1, l, mid);
build(x<<1|1, mid+1, r);
pushup(x);
}
void pushdown(int x)
{
int ls = x<<1, rs = x<<1|1;
t[ls].v = t[rs].v = t[x].tag;
t[ls].tag = t[rs].tag = t[x].tag;
t[x].tag = 0;
}
void update(int x, int l, int r, int L, int R, int v)
{
if(L <= l && r <= R)
{
t[x].v = v; t[x].tag = v;
return;
}
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1;
if(L <= mid) update(x<<1, l, mid, L, R, v);
if(R > mid) update(x<<1|1, mid+1, r, L, R, v);
pushup(x);
}
int query(int x, int l, int r, int L, int R)
{
if(L <= l && r <= R) return t[x].v;
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1, ans = inf;
if(L <= mid) ans = min(ans, query(x<<1, l, mid, L, R));
if(R > mid) ans = min(ans, query(x<<1|1, mid+1, r, L, R));
return ans;
}
}t;
void solve1()
{
int N = n * k;
for(int i=n+1; i<=N; i++) a[i] = a[i-n];
t.build(1, 1, N);
Q = read();
while(Q--)
{
int opt = read();
if(opt == 1)
{
int l = read(), r = read(), v = read();
t.update(1, 1, N, l, r, v);
}
else
{
int l = read(), r = read();
printf("%d\n", t.query(1, 1, N, l, r));
}
}
exit(0);
}
struct ask
{
int id, opt, l, r, v, bel;
bool operator < (const ask &T) const
{
if(bel == T.bel) return id < T.id;
return bel < T.bel;
}
}q[maxQ<<2];//依然有可能RE
void split(int now)
{
int zl = (q[now].l-1)/n+1, zr = (q[now].r-1)/n+1;
if(zl == zr)
{
q[now].l = (q[now].l-1)%n+1, q[now].r = (q[now].r-1)%n+1;
q[now].bel = zl; return;
}
ask res = q[now];
q[now].r = n; q[now].bel = zl; q[now].l = (res.l-1) % n + 1;
cnt++; q[cnt] = res;
q[cnt].l = 1; q[cnt].bel = zr; q[cnt].r = (res.r-1) % n + 1;
if(zl + 1 == zr) return;
for(int i=zl+1; i<zr; i++)
{
cnt++; q[cnt] = res;
q[cnt].l = 1, q[cnt].r = n;
q[cnt].bel = i;
}
}
int main()
{
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
n = read(); k = read();
for(int i=1; i<=n; i++) a[i] = read();
if(n * k <= 1e5) solve1();
Q = read(); cnt = Q;
for(int i=1; i<=Q; i++)
{
q[i].opt = read(); q[i].id = i;
q[i].l = read(), q[i].r = read();
if(q[i].opt == 1) q[i].v = read();
split(i);
}
for(int i=1; i<=Q; i++)
{
if(q[i].opt == 2) ans[i] = inf;
}
sort(q+1, q+1+cnt);
t.build(1, 1, n);
if(q[1].opt == 1) t.update(1, 1, n, q[1].l, q[1].r, q[1].v);
else ans[q[1].id] = t.query(1, 1, n, q[1].l, q[1].r);
for(int i=2; i<=cnt; i++)
{
if(q[i].bel != q[i-1].bel) t.build(1, 1, n);
if(q[i].opt == 1) t.update(1, 1, n, q[i].l, q[i].r, q[i].v);
else ans[q[i].id] = min(ans[q[i].id], t.query(1, 1, n, q[i].l, q[i].r));
}
for(int i=1; i<=Q; i++)
{
if(ans[i]) printf("%d\n", ans[i]);
}
return 0;
}
有没有由于数组来不下RE我不知道但是MLE了是真的。后来打算放弃记录问题直接划分:
愉快地T掉了。。。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 2, inf = 0x3f3f3f3f;
int n, a[maxn], k, Q, ans[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 seg
{
struct node
{
int v, tag;
}t[maxn<<2];
void pushup(int x)
{
t[x].v = min(t[x<<1].v, t[x<<1|1].v);
}
void build(int x, int l, int r)
{
t[x].tag = 0;
if(l == r)
{
t[x].v = a[l]; return;
}
int mid = (l + r) >> 1;
build(x<<1, l, mid);
build(x<<1|1, mid+1, r);
pushup(x);
}
void pushdown(int x)
{
int ls = x<<1, rs = x<<1|1;
t[ls].v = t[rs].v = t[x].tag;
t[ls].tag = t[rs].tag = t[x].tag;
t[x].tag = 0;
}
void update(int x, int l, int r, int L, int R, int v)
{
if(L <= l && r <= R)
{
t[x].v = v; t[x].tag = v;
return;
}
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1;
if(L <= mid) update(x<<1, l, mid, L, R, v);
if(R > mid) update(x<<1|1, mid+1, r, L, R, v);
pushup(x);
}
int query(int x, int l, int r, int L, int R)
{
if(L <= l && r <= R) return t[x].v;
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1, ans = inf;
if(L <= mid) ans = min(ans, query(x<<1, l, mid, L, R));
if(R > mid) ans = min(ans, query(x<<1|1, mid+1, r, L, R));
return ans;
}
}t;
void solve1()
{
int N = n * k;
for(int i=n+1; i<=N; i++) a[i] = a[i-n];
t.build(1, 1, N);
Q = read();
while(Q--)
{
int opt = read();
if(opt == 1)
{
int l = read(), r = read(), v = read();
t.update(1, 1, N, l, r, v);
}
else
{
int l = read(), r = read();
printf("%d\n", t.query(1, 1, N, l, r));
}
}
exit(0);
}
struct ask
{
int opt, l, r, v;
}q[maxn];
int main()
{
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
n = read(); k = read();
for(int i=1; i<=n; i++) a[i] = read();
if(n * k <= 1e5) solve1();
Q = read();
for(int i=1; i<=Q; i++)
{
q[i].opt = read();
q[i].l = read(), q[i].r = read();
if(q[i].opt == 1) q[i].v = read();
}
for(int i=1; i<=Q; i++)
{
if(q[i].opt == 2) ans[i] = inf;
}
for(int i=1; i<=k; i++)
{
t.build(1, 1, n);
for(int j=1; j<=Q; j++)
{
int zl = (q[j].l-1)/n+1, zr = (q[j].r-1)/n+1;
if(zl > i || zr < i) continue;
int l = zl == i ? (q[j].l-1)%n+1 : 1, r = zr == i ? (q[j].r-1)%n+1 : n;
if(q[j].opt == 1) t.update(1, 1, n, l, r, q[j].v);
else ans[j] = min(ans[j], t.query(1, 1, n, l, r));
}
}
for(int i=1; i<=Q; i++)
{
if(ans[i]) printf("%d\n", ans[i]);
}
return 0;
}
比赛结束后就鹤了一下:
建立一棵庞大的动态开点线段树,被覆盖过的在线段树上查,剩下的单独搞个ST表查。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 2, inf = 0x3f3f3f3f;
int n, a[maxn], k, Q, N, rt;
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 Table
{
int d[maxn][18];
void init()
{
for(int i=1; i<=n; i++) d[i][0] = a[i];
for(int j=1; (1<<j)<=n; j++)
{
for(int i=1; i+(1<<j)-1<=n; i++)
{
d[i][j] = min(d[i][j-1], d[i+(1<<j-1)][j-1]);
}
}
}
int query(int l, int r)
{
int k = 0;
while((1<<k+1) <= r-l+1) k++;
return min(d[l][k], d[r-(1<<k)+1][k]);
}
}st;
struct seg
{
struct node
{
int v, tag, mv;
}t[maxn<<2];
int lc[maxn<<2], rc[maxn<<2];
int tot;
void pushup(int x)
{
int ans = inf;
if(lc[x]) ans = t[lc[x]].v;
if(rc[x]) ans = min(ans, t[rc[x]].v);
t[x].v = ans;
}
void pushdown(int x)
{
if(!lc[x]) lc[x] = ++tot;
if(!rc[x]) rc[x] = ++tot;
t[lc[x]].tag = t[rc[x]].tag = t[x].tag;
t[lc[x]].v = t[rc[x]].v = t[x].tag;
t[lc[x]].mv = t[rc[x]].mv = 1;
t[x].tag = 0;
}
void update(int &x, int l, int r, int L, int R, int v)
{
if(!x) x = ++tot;
if(!rt) rt = x;
if(L <= l && r <= R)
{
t[x].v = v; t[x].tag = v; t[x].mv = 1;
return;
}
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1;
if(L <= mid) update(lc[x], l, mid, L, R, v);
if(R > mid) update(rc[x], mid+1, r, L, R, v);
pushup(x);
}
int query(int x, int l, int r, int L, int R)
{
if(!x && L <= l && r <= R)
{
int ll = (l-1)%n+1, rr = (r-1)%n+1;
int zl = (l-1)/n+1, zr = (r-1)/n+1;
if(zl == zr) return st.query(ll, rr);
else return min(st.query(ll, n), st.query(1, rr));
}
if(L <= l && r <= R && t[x].mv) return t[x].v;
if(t[x].tag) pushdown(x);
int mid = (l + r) >> 1, ans = inf;
if(L <= mid) ans = min(ans, query(lc[x], l, mid, L, R));
if(R > mid) ans = min(ans, query(rc[x], mid+1, r, L, R));
return ans;
}
}t;
int main()
{
freopen("data.in", "r", stdin);
freopen("data.out", "w", stdout);
n = read(); k = read(); N = n * k;
for(int i=1; i<=n; i++) a[i] = read();
st.init();
Q = read();
while(Q--)
{
int opt = read();
if(opt == 1)
{
int l = read(), r = read(), v = read();
t.update(rt, 1, N, l, r, v);
}
else if(opt == 2)
{
int l = read(), r = read();
printf("%d\n", t.query(rt, 1, N, l, r));
}
}
return 0;
}
C. 信息学的尽头
我也不知道我就跑了个最短路怎么还MLE 0了!?
然而就假设最短路有分:
要不是盲猜CR不会我怎么可能想到了基环树和换根dp之后打算写个暴力不做了
然而她切了
%%%CR
不过好像我好好想的话依然想不到具体该怎么办
怎么就连个找环都不会了
怎么就算个贡献都不知道加谁了
%%%CR
无奈至极地去鹤了她的两版code除了函数名之外没什么区别了
同时心情真的很糟糕
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 2, inf = 0x3f3f3f3f;
int n, dfn[maxn], num, h[maxn], ccf, fa[maxn], siz[maxn];
ll pdh[maxn], dh[maxn], dep[maxn], sdep[maxn], ans[maxn];
bool inc[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 edge
{
int nxt, to, w;
}e[maxn<<1];
int head[maxn], len;
void add(int x, int y, int w)
{
e[++len].to = y; e[len].nxt = head[x]; e[len].w = w;
head[x] = len;
}
void Attend_NOI(int x, int ff)
{
fa[x] = ff;
dfn[x] = ++num;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff) continue;
if(!dfn[v]) pdh[v] = e[i].w, Attend_NOI(v, x);
else
{
if(dfn[v] < dfn[x])
{
int st = x;
while(st != v)
{
h[++ccf] = st;
dh[ccf] = pdh[st];
st = fa[st];
}
h[++ccf] = v;
dh[ccf] = e[i].w;
}
}
}
}
void IwantAg(int x, int ff)
{
sdep[x] = dep[x];
siz[x] = 1;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff || inc[v]) continue;
dep[v] = dep[x] + e[i].w;
IwantAg(v, x);
siz[x] += siz[v];
sdep[x] += sdep[v];
}
}
ll AuIsBest(int pos)
{
ll ret = 0;
for(int i=1; i<=ccf; i++)
{
if(i == pos) continue;
ll dev = 0;
if(i < pos) dev = min(dh[i+ccf]-dh[pos], dh[pos]-dh[i]);
else dev = min(dh[i+ccf]-dh[pos+ccf], dh[pos+ccf]-dh[i]);
ret += dev * siz[h[i]];
}
return ret;
}
void CTSC(int x, int ff, ll val)
{
ans[x] = val;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff || inc[v]) continue;
CTSC(v, x, val+(n-siz[v]*2)*e[i].w);
}
}
int main()
{
freopen("end.in", "r", stdin);
freopen("end.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
Attend_NOI(1, 0);
for(int i=ccf+1; i>=1; i--) dh[i] = dh[i-1];
int rp = ccf + 1;
for(int i=ccf+2; i<=ccf*2; i++)
{
rp++; dh[rp] = dh[rp-ccf];
}
for(int i=2; i<=ccf*2; i++) dh[i] = dh[i-1] + dh[i];
for(int i=ccf+1; i<=ccf*2; i++) h[i] = h[i-ccf];
for(int i=1; i<=ccf*2; i++) inc[h[i]] = 1;
ll Sum_ep = 0;
for(int i=1; i<=ccf; i++) IwantAg(h[i], 0), Sum_ep += sdep[h[i]];
for(int i=1; i<=ccf; i++)
{
ll sum_ep = AuIsBest(i);
sum_ep += Sum_ep;
CTSC(h[i], 0, sum_ep);
}
for(int i=1; i<=n; i++) printf("%lld ", ans[i]);
return 0;
}
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 2, inf = 0x3f3f3f3f;
int n, dfn[maxn], num, h[maxn], ccf, fa[maxn], siz[maxn];
ll pdh[maxn], dh[maxn], dep[maxn], sdep[maxn], ans[maxn];
bool inc[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 edge
{
int nxt, to, w;
}e[maxn<<1];
int head[maxn], len;
void add(int x, int y, int w)
{
e[++len].to = y; e[len].nxt = head[x]; e[len].w = w;
head[x] = len;
}
void Attend_NOI(int x, int ff)
{
fa[x] = ff;
dfn[x] = ++num;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff) continue;
if(!dfn[v]) pdh[v] = e[i].w, Attend_NOI(v, x);
else
{
if(dfn[v] < dfn[x])
{
int st = x;
while(st != v)
{
h[++ccf] = st;
dh[ccf] = pdh[st];
st = fa[st];
}
h[++ccf] = v;
dh[ccf] = e[i].w;
}
}
}
}
void IwantAg(int x, int ff)
{
sdep[x] = dep[x];
siz[x] = 1;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff || inc[v]) continue;
dep[v] = dep[x] + e[i].w;
IwantAg(v, x);
siz[x] += siz[v];
sdep[x] += sdep[v];
}
}
ll ssiz[maxn], sdis[maxn];
ll AuIsBest(int pos)
{
ll ret = 0;
/*for(int i=1; i<=ccf; i++)
{
if(i == pos) continue;
ll dev = 0;
if(i < pos) dev = min(dh[i+ccf]-dh[pos], dh[pos]-dh[i]);
else dev = min(dh[i+ccf]-dh[pos+ccf], dh[pos+ccf]-dh[i]);
ret += dev * siz[h[i]];
}*/
//又鹤了,,,,,,然而又鹤错了,,,
int Pos = pos + ccf;
int l = pos, r = Pos - 1;
while(l < r)
{
int mid = (l + r + 1) >> 1;
if(dh[mid]-dh[pos] <= dh[Pos]-dh[mid]) l = mid;
else r = mid - 1;
}
if(l > pos) ret = sdis[l]-sdis[pos]-dh[pos]*(ssiz[l]-ssiz[pos]);
if(l < Pos-1) ret += dh[Pos]*(ssiz[Pos-1]-ssiz[l])-sdis[Pos-1]+sdis[l];
return ret;
}
void CTSC(int x, int ff, ll val)
{
ans[x] = val;
for(int i=head[x]; i; i=e[i].nxt)
{
int v = e[i].to;
if(v == ff || inc[v]) continue;
CTSC(v, x, val+(n-siz[v]*2)*e[i].w);
}
}
int main()
{
freopen("end.in", "r", stdin);
freopen("end.out", "w", stdout);
n = read();
for(int i=1; i<=n; i++)
{
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
Attend_NOI(1, 0);
for(int i=ccf+1; i>=1; i--) dh[i] = dh[i-1];
int rp = ccf + 1;
for(int i=ccf+2; i<=ccf*2; i++)
{
rp++; dh[rp] = dh[rp-ccf];
}
for(int i=2; i<=ccf*2; i++) dh[i] = dh[i-1] + dh[i];
for(int i=ccf+1; i<=ccf*2; i++) h[i] = h[i-ccf];
for(int i=1; i<=ccf*2; i++) inc[h[i]] = 1;
ll Sum_ep = 0;
for(int i=1; i<=ccf; i++) IwantAg(h[i], 0), Sum_ep += sdep[h[i]];
for(int i=1; i<=ccf*2; i++)
{
ssiz[i] = ssiz[i-1] + siz[h[i]];
sdis[i] = sdis[i-1] + dh[i] * siz[h[i]];
}
for(int i=1; i<=ccf; i++)
{
ll sum_ep = AuIsBest(i);
sum_ep += Sum_ep;
CTSC(h[i], 0, sum_ep);
}
for(int i=1; i<=n; i++) printf("%lld ", ans[i]);
return 0;
}
同时依然不服她,%了也不服,输很多次也不服,你就当我是个死鸭子吧,就是化成灰变成烟随风散了也要嘴硬的……
D. 球对称薛定谔方程
组织了一下语言发现还是想不出什么和这篇题解不一样的说法,那就……
这种堆的方案数的求法让我想到了多叉堆,公式的差别在于有没有枚举接在一起的另一棵树根节点的权值。关于为什么转移时非要枚举1号点的权值与子树大小,我感觉和有一种二进制拆开的转移让其中一部分减掉lowbit差不多,就是怎么拆都行选一个最好拆的,只是需要枚举了其中一棵子树的信息具体哪棵树并不重要,但是标号最小的儿子权值可以从j+1开始比较方便枚举……
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 305, inf = 0x3f3f3f3f;
int n, k, P, C[maxn][maxn], f[maxn][maxn], s[maxn][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;
}
int main()
{
freopen("seq.in", "r", stdin);
freopen("seq.out", "w", stdout);
n = read(); k = read(); P = read();
for(int i=0; i<=n; i++)
{
C[i][0] = 1;
for(int j=1; j<=i; j++)
{
C[i][j] = ((ll)C[i-1][j] + C[i-1][j-1]) % P;
}
}
for(int i=0; i<=k; i++) f[1][i] = 1, s[1][i] = k-i+1;
for(int i=2; i<=n+1; i++)
{
for(int j=0; j<=k; j++) for(int l=1; l<i; l++) f[i][j] = (f[i][j]+1ll*f[i-l][j]*s[l][j+1]%P*C[i-2][l-1]%P)%P;
for(int j=k; j; j--) s[i][j] = ((ll)s[i][j+1]+f[i][j])%P;
}
printf("%d\n", f[n+1][0]);
return 0;
}
标签:ch,2022NOIPA,int,long,27,maxn,联测,ans,getchar From: https://www.cnblogs.com/Catherine2006/p/16887902.html