T1

感觉有点神,题意就是给一棵树,求有多少不同的点分方案。20200207模拟赛 题解_git

题解就是考虑用一条边合并两棵树时,他们的点分树能结合成什么样。

20200207模拟赛 题解_git_02


那么就可以考虑DP了:

20200207模拟赛 题解_git_03


代码挺短。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template<class T>inline void read(T &x) {
char ch; while(!isdigit(ch=getchar()));
for(x = ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
}
const int mod = 1e9 + 7, MAXN = 5005;
int n, c[MAXN][MAXN], f[MAXN][MAXN], sz[MAXN];
vector<int>e[MAXN];
void dp(int u, int ff) {
f[u][1] = sz[u] = 1;
for(int o = e[u].size()-1, v; o >= 0; --o)
if((v=e[u][o]) != ff) {
dp(v, u);
for(int i = sz[u]+sz[v]; i >= 1; --i) {
f[u][i] = 1ll * f[u][i] * f[v][0] % mod;
for(int j = max(1, i-sz[v]); j < i && j <= sz[u]; ++j)
f[u][i] = (f[u][i] + 1ll * f[u][j] * f[v][i-j] % mod * c[i-1][j-1]) % mod;
}
sz[u] += sz[v];

}
for(int i = sz[u]-1; i >= 0; --i)
f[u][i] = (f[u][i] + f[u][i+1]) % mod;
}
int main() {
read(n);
for(int i = 1, x, y; i < n; ++i)
read(x), read(y), e[x].push_back(y), e[y].push_back(x);
c[0][0] = 1;
for(int i = 1; i <= n; ++i) {
c[i][0] = c[i][i] = 1;
for(int j = 1; j < i; ++j)
c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
}
dp(1, 0);
printf("%d\n", f[1][1]);
}

T2

考场上想到了,发现前缀就是trie上祖先关系。然后dfs序,所以就是三维数点问题,cdq套个BIT就过了。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int C = 26;
const int MAXN = 500005;
int n, m, pos[MAXN][3], Z;
char s[MAXN], op[2], al[2];
struct trie {
int ch[MAXN][C], tot, dfn[MAXN], in[MAXN], out[MAXN];
bool vis[MAXN];
int ins() {
int r = 1, len = strlen(s+1);
for(int i = 1; i <= len; ++i) {
if(!ch[r][s[i]-'a']) ch[r][s[i]-'a'] = ++tot;
r = ch[r][s[i]-'a'];
}
vis[r] = 1;
return r;
}
int tmr;
void dfs(int u) {
in[u] = tmr+1;
if(vis[u]) dfn[u] = ++tmr;
for(int i = 0; i < C; ++i)
if(ch[u][i]) dfs(ch[u][i]);
out[u] = tmr;
}
int cur, indx, seq[MAXN];
void build() { dfs(1); cur = 1; seq[++indx] = 1; }
void move() {
if(op[0] == '-') cur = seq[--indx];
else seq[++indx] = cur = ch[cur][al[0]-'a'];
}
}T[3];
int ans[MAXN], cnt;
struct Q {
int x, yl, yr, zl, zr, f, id;
inline bool operator <(const Q &o)const {
return x == o.x ? id < o.id : x < o.x;
}
}q[MAXN*3];
struct node {
int y, zl, zr, f, id;
inline bool operator <(const node &o)const {
return y == o.y ? id < o.id : y < o.y;
}
}a[MAXN*6];
int t[MAXN], tim, vis[MAXN];
inline void upd(int x) {
while(x <= Z) {
if(vis[x] != tim) vis[x] = tim, t[x] = 0;
++t[x]; x += x&-x;
}
}
inline int qry(int x) {
int re = 0;
while(x) {
if(vis[x] != tim) vis[x] = tim, t[x] = 0;
re += t[x]; x -= x&-x;
}
return re;
}
void solve(int l, int r) {
if(l == r) return;
int mid = (l + r) >> 1, tp = 0;
for(int i = l; i <= mid; ++i)
if(!q[i].id) a[++tp] = (node){ q[i].yl, q[i].zl, 0, 0, 0 };
for(int i = mid+1; i <= r; ++i)
if(q[i].id) {
a[++tp] = (node){ q[i].yr, q[i].zl, q[i].zr, q[i].f, q[i].id };
if(q[i].yl>1)a[++tp] = (node){ q[i].yl-1, q[i].zl, q[i].zr, -q[i].f, q[i].id };
}
sort(a + 1, a + tp + 1);
for(int i = 1; i <= tp; ++i) {
if(!a[i].id) upd(a[i].zl);
else ans[a[i].id] += a[i].f * (qry(a[i].zr)-qry(a[i].zl-1));
}
++tim;
solve(l, mid);
solve(mid+1, r);
}

int main() {
scanf("%d", &n);
T[0].tot = T[1].tot = T[2].tot = 1;
for(int i = 1; i <= n; ++i) {
scanf("%s", s+1);
pos[i][0] = T[0].ins();
scanf("%s", s+1);
pos[i][1] = T[1].ins();
scanf("%s", s+1);
pos[i][2] = T[2].ins();
}
T[0].build();
T[1].build();
T[2].build(); Z = T[2].tmr;
scanf("%d", &m);
for(int i = 1, x; i <= m; ++i) {
scanf("%s%d", op, &x); --x;
if(op[0]=='+')scanf("%s", al);
T[x].move();
if(T[0].cur && T[1].cur && T[2].cur) {
int l0 = T[0].in[T[0].cur], r0 = T[0].out[T[0].cur];
int l1 = T[1].in[T[1].cur], r1 = T[1].out[T[1].cur];
int l2 = T[2].in[T[2].cur], r2 = T[2].out[T[2].cur];
if(l0 <= r0 && l1 <= r1 && l2 <= r2) {
q[++cnt] = (Q) { r0, l1, r1, l2, r2, 1, i };
if(l0>1) q[++cnt] = (Q) { l0-1, l1, r1, l2, r2, -1, i };
}
}
}
for(int i = 1; i <= n; ++i)
q[++cnt] = (Q){ T[0].dfn[pos[i][0]], T[1].dfn[pos[i][1]], 0, T[2].dfn[pos[i][2]], 0, 0, 0 };
sort(q + 1, q + cnt + 1);
solve(1, cnt);
for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
}

T3

稍稍推式子能得到20200207模拟赛 题解_#include_04的算法。(数论gcd这块感觉还不是很会啊。)

20200207模拟赛 题解_#include_05


博客中写道要模20200207模拟赛 题解_c++_06,但这样还要去求一遍20200207模拟赛 题解_#include_07;其实可以直接模20200207模拟赛 题解_git_08就行了,因为20200207模拟赛 题解_#include_07一定是20200207模拟赛 题解_c++_10的因数。

要特判20200207模拟赛 题解_#include_11种情况。一是20200207模拟赛 题解_git_12;二是转换后的上面题解中写的20200207模拟赛 题解_git_13(下面代码中写的20200207模拟赛 题解_#include_14).

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
template<class T>inline void read(T &x) {
char ch; while(!isdigit(ch=getchar()));
for(x = ch-'0'; isdigit(ch=getchar()); x=x*10+ch-'0');
}
const int mod = 998244353;
LL a, b, c, d, P, F1, F2;
struct mat {
int a[2][2];
mat(){a[0][0]=a[0][1]=a[1][0]=a[1][1]=0;}
inline mat operator *(const mat &o) {
mat re;
for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
for(int k = 0; k < 2; ++k)
re.a[i][j] = (re.a[i][j] + 1ll*a[i][k]*o.a[k][j]) % P;
return re;
}
inline mat operator ^(LL k) {
mat re, A = (*this); re.a[0][0] = re.a[1][1] = 1;
while(k) {
if(k&1) re = re * A;
A = A * A; k >>= 1;
}
return re;
}
}tr;
void fib(LL n, LL p) { P = p;
mat A; A.a[0][0] = 1;
A = (tr ^ n) * A;
F2 = A.a[0][0];
F1 = A.a[1][0];
}
LL n;
int main() {
tr.a[0][0] = tr.a[0][1] = tr.a[1][0] = 1;
int T; read(T);
while(T--) {
read(n), read(a), read(b), read(c), read(d);
if(!a && !c) { fib(n, mod); printf("%lld\n", 1ll * __gcd(b, d) * F2 % mod); continue; }
while(a && c) {
if(a < c) swap(a, c), swap(b, d);
LL t = a/c; a -= t*c, b -= t*d;
}
if(a < c) swap(a, c), swap(b, d);
d = abs(d); LL p = (!d) ? mod : a*d; fib(n, p);
LL A = ((1ll * a % p * F1 + 1ll* b % p * F2) % p + p) % p;
if(!d) { printf("%lld\n", A); continue; }
LL B = 1ll* d % p * F2 % p;
printf("%lld\n", __gcd(__gcd(A, p), __gcd(B, p)) % mod);
}
}