三道大原题,我就直接写了
T1 scoi2016 背单词
建一个 Trie 树,递推出每个点子树里单词节点的数量,把单词节点拿出来建个树形结构,所有单词节点向他上面最近的单词节点连边,每次贪心往比较小的那边走就可以了
不建树是错的,因为会把不同的单词节点算成一个
例如:

比如左边四个单词节点就被算到了一起,应该先从左边一个一个走,镘走了右边(#上香

#include<bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar())if(ch == '-') f=-f;
for(;isdigit(ch);ch=getchar())x = 10 * x + ch - '0';
return x * f;
}
const int maxn = 1000010;
int n;
char str[maxn];
int danger[maxn], id[maxn], tr[maxn][26], dfn, size[maxn];
vector<int> sons[maxn];
void Insert(char *str) {
int len = strlen(str), now = 0;
for(int i=len-1;~i;i--) {
int pp = str[i] - 'a';
if(!tr[now][pp]) tr[now][pp] = ++dfn;
now = tr[now][pp];
}
danger[now] = 1;
}
int cmp(int x, int y) {return size[x] < size[y];}
int pnt = 1;
void dfs(int x, int cur) {
if(danger[x]) sons[cur].push_back(++pnt), size[cur = pnt] = 1;
rep(i, 0, 25) if(tr[x][i]) dfs(tr[x][i], cur);
}
void makesize(int x) {
for(int i=0;i<(int)sons[x].size();i++) {
makesize(sons[x][i]);
size[x] += size[sons[x][i]];
}
}
int ind[maxn], pre, _tim;
LL ans;
void solve(int x, int wfa) {
_tim++; ans += _tim - wfa; wfa = _tim;
sort(sons[x].begin(), sons[x].end(), cmp);
for(int i=0;i<(int)sons[x].size();i++) solve(sons[x][i], wfa);
}
int main() {
//freopen("words.in","r",stdin);
//freopen("words.out","w",stdout);
n = read();
rep(i, 1, n) {
scanf("%s", str);
Insert(str);
} dfs(0, 1); makesize(1);
//return 0;
solve(1, 1);
cout << ans << endl;
}
T2 sdoi2017 树点染色
LCT + 线段树套路题,30 分钟码完

#include<bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i ## end; ++i)
#define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i ## end; --i)
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar())if(ch == '-') f=-f;
for(;isdigit(ch);ch=getchar())x = 10 * x + ch - '0';
return x * f;
}
const int maxn = 300010;
int n, q;
int first[maxn], to[maxn << 1], nx[maxn << 1], cnt;
inline void add(int u, int v) {
to[++cnt] = v;
nx[cnt] = first[u];
first[u] = cnt;
}
inline void ins(int u, int v) {add(u, v); add(v, u);}
int anc[maxn], size[maxn], bl[maxn], pos[maxn], _tim, dep[maxn];
inline void dfs(int x) {
size[x] = 1;
for(int i=first[x];i;i=nx[i]) {
if(to[i] == anc[x]) continue;
anc[to[i]] = x; dep[to[i]] = dep[x] + 1;
dfs(to[i]); size[x] += size[to[i]];
}
}
inline void dfs2(int x, int col) {
bl[x] = col; int k = 0; pos[x] = ++_tim;
for(int i=first[x];i;i=nx[i])
if(to[i] != anc[x] && size[to[i]] > size[k]) k = to[i];
if(!k) return;
dfs2(k, col);
for(int i=first[x];i;i=nx[i])
if(to[i] != anc[x] && to[i] != k) dfs2(to[i], to[i]);
}
int seg[maxn << 2], tag[maxn << 2], mxseg[maxn << 2];
inline void pushdown_seg(int x, int l, int r) {
if(tag[x]) {
int mid = (l + r) >> 1;
tag[x << 1] += tag[x]; tag[x << 1| 1] += tag[x];
mxseg[x << 1] += tag[x]; mxseg[x << 1| 1] += tag[x];
tag[x] = 0;
}
}
inline void update(int x, int l, int r, int L, int R, int v) {
if(L <= l && r <= R) {
tag[x] += v;
mxseg[x] += v;
return;
}
pushdown_seg(x, l, r);
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);
mxseg[x] = max(mxseg[x << 1], mxseg[x << 1 | 1]);
}
inline int querymx(int x, int l, int r, int L, int R) {
if(L <= l && r <= R) {
return mxseg[x];
}
pushdown_seg(x, l, r);
int mid = (l + r) >> 1, ans = 0;
if(L <= mid) ans = max(ans, querymx(x << 1, l, mid, L, R));
if(R > mid) ans = max(ans, querymx(x << 1 | 1, mid + 1, r, L, R));
return ans;
}
inline void Mod(int x, int opt) {
update(1, 1, n, pos[x], pos[x] + size[x] - 1, opt);
}
inline int lca(int x, int y) {
while(bl[x] != bl[y]) {
if(dep[bl[x]] < dep[bl[y]]) swap(x, y);
x = anc[bl[x]];
}
return dep[x] < dep[y] ? x : y;
}
inline int qn(int x) {
return querymx(1, 1, n, pos[x], pos[x] + size[x] - 1);
}
#define ls (ch[x][0])
#define rs (ch[x][1])
int ch[maxn][2], fa[maxn], st[maxn], top, tg[maxn];
inline int isroot(int x) {return (ch[fa[x]][0] != x) && (ch[fa[x]][1] != x);}
inline void pushup(int x) {
tg[x] = x;
if(tg[ls]) tg[x] = tg[ls];
}
inline void rotate(int x) {
int y = fa[x], z = fa[y];
int l = (ch[y][1] == x), r = l ^ 1;
if(!isroot(y))ch[z][ch[z][1] == y] = x;
fa[x] = z; fa[y] = x; fa[ch[x][r]] = y;
ch[y][l] = ch[x][r]; ch[x][r] = y;
pushup(y); pushup(x);
}
inline void splay(int x) {
while(!isroot(x)) {
int y = fa[x], z = fa[y];
if(!isroot(y)) {
if(ch[z][0] == y ^ ch[y][0] == x) rotate(x);
else rotate(y);
}
rotate(x);
}
}
inline void access(int x) {
for(int y=0;x;y=x,x=fa[x]) {
splay(x); int tmp;
if(rs) {tmp = tg[rs];Mod(tmp, 1);}
if(y) {tmp = tg[y];Mod(tmp, -1);}
rs = y; pushup(rs);
}
}
int main() {
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
dep[1] = 1;
n = read(), q = read();
for(int i=2;i<=n;i++) {
int u = read(), v = read();
ins(u, v);
} dfs(1); dfs2(1, 1);
rep(i, 1, n) {
fa[i] = anc[i]; tg[i] = i;
update(1, 1, n, pos[i], pos[i], dep[i]);
}
while(q--) {
int opt = read();
if(opt == 1) {
int x = read();
access(x);
}
if(opt == 2) {
int x = read(), y = read();
int hx = lca(x, y);
int t1 = querymx(1, 1, n, pos[x], pos[x]), t2 = querymx(1, 1, n, pos[y], pos[y]);
int t3 = querymx(1, 1, n, pos[hx], pos[hx]);
printf("%d\n", t1 + t2 - (t3 << 1) + 1);
}
if(opt == 3) {
int x = read();
printf("%d\n", qn(x));
}
}
}
T3 hnoi2017 抛硬币
考场上只写了 30 ,还是太菜了 qnq

#include<bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for(register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for(register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
int x = 0, f = 1; char ch = getchar();
for(;!isdigit(ch);ch=getchar())if(ch == '-') f=-f;
for(;isdigit(ch);ch=getchar())x = 10 * x + ch - '0';
return x * f;
}
const int maxn = 100010;
LL a, b;
int mod;
int ksm(int x, int t) {
int res = 1;
while(t) {
if(t & 1) res = 1LL * res * x % mod;
x = 1LL * x * x % mod;
t = t >> 1;
} return res;
}
namespace solve1 {
int cc[50][50];
void solve() {
cc[0][0] = 1;
rep(i, 1, 30) cc[i][0] = 1;
rep(i, 1, 30) rep(j, 1, 30) cc[i][j] = (cc[i - 1][j] + cc[i - 1][j - 1]) % mod;
int maxstate = (1 << a);
int ans = 0;
for(int S=1;S<maxstate;S++) {
int nS = (LL)__builtin_popcount(S) - 1;
dwn(i, nS, 0) (ans += cc[b][i]) %= mod;
}
if(mod == 10) printf("%01d", ans);
if(mod == 100) printf("%02d", ans);
if(mod == 1000) printf("%03d", ans);
if(mod == 10000) printf("%04d", ans);
if(mod == 100000) printf("%05d", ans);
if(mod == 1000000) printf("%06d", ans);
if(mod == 10000000) printf("%07d", ans);
if(mod == 100000000) printf("%08d", ans);
if(mod == 1000000000) printf("%09d", ans);
cout << endl;
}
}
namespace solve2 {
int cc[500][500];
void solve() {
cc[0][0] = 1;
rep(i, 1, 130) cc[i][0] = 1;
rep(i, 1, 130) rep(j, 1, 130) cc[i][j] = (cc[i - 1][j] + cc[i - 1][j - 1]) % mod;
int ans = 0;
rep(i, 1, a) {
int res = 0;
rep(j, 0, i-1) (res += cc[b][j]) %= mod;
(ans += (1LL * cc[a][i] * res) % mod) %= mod;
}
if(mod == 10) printf("%01d", ans);
if(mod == 100) printf("%02d", ans);
if(mod == 1000) printf("%03d", ans);
if(mod == 10000) printf("%04d", ans);
if(mod == 100000) printf("%05d", ans);
if(mod == 1000000) printf("%06d", ans);
if(mod == 10000000) printf("%07d", ans);
if(mod == 100000000) printf("%08d", ans);
if(mod == 1000000000) printf("%09d", ans);
cout << endl;
}
}
int main() {
while(scanf("%lld%lld%d", &a, &b, &mod) == 3 ) {
mod = pow(10, mod);
if(a <= 100 && b <= 100) solve2::solve();
else puts("QAQ");
}
}
30pts就是:
$\sum\limits_{i=0}^a \sum\limits_{j=0}^{b} [i > j] \times C_a^i \times C_b^j$
也就是 $\sum\limits_{i=0}^a \sum\limits_{j=0}^{a-i} C_a^{i+j} \times C_b^{i-j}$
然后根据范德蒙德卷积(链接里的第一个)得到原式就是:$\sum\limits_{i=b+1}^{b+a} C_{a+b}^i$
然后就是组合数取模方面的东西了
先把式子拆成两部分,记 $c = \lceil \frac{a+b}{2} \rceil$,则原式 = $\sum\limits_{i=c}^{a+b} C_{a+b}^i + \sum\limits_{i=b+1}^{c} C_{a+b}^i$
后一项可以暴力,前一项当 $a+b$ 是奇数的时候是杨辉三角的一行和,也就是 $2^{a+b-1}$,当 $a+b$ 是偶数的时候,是 $2^{a+b-1} - \frac{1}{2} \times C_{a+b}^{\frac{a+b}{2}}$
然后需要扩展 lucas 求组合数,然而不会
。。
补档:扩展 lucas
要求 $C_n^m \space mod \space p$,$p$ 不一定是质数
我们可以唯一分解然后用 excrt 合并一下,现在问题就是求 $C_n^m \space mod \space p^k$,$p$ 是质数
根据组合数的定义式,我们只要快速求出模意义下的阶乘就可以了
举个简单的例子:
$22! \space mod \space 3^2$
发现 $22! = (3^7) \times (1 \times 2 \times 3 \times ... \times 7) \times (1 \times 2 \times 4 \times 5 \times 7 \times 8 \times 10 \times 11 \times 13 \times 14 \times 16 \times 17 \times 19 \times 22)$
第一个括号是 $p^{\lfloor \frac{n}{p} \rfloor}$,第二个括号是 $(\lfloor \frac{n}{p} \rfloor) !$ ,递归解决,第三个括号在模意义下存在一个循环,循环了 $\lfloor \frac{n}{p^k} \rfloor$ 次,每次是 $\prod\limits_{i=1}^{p^k} i \times [gcd(i,p)==1]$ ,可以先算这一个循环,然后算它的 $\lfloor \frac{n}{p^k} \rfloor$ 次幂,最后还剩了 $n \space mod \space p^k$ 项,注意到每一项有贡献当且仅当它与 $p$ 互质,暴力算即可
算组合数的时候,可以把所有 $p$ 提到分数外面,这样就有逆元了,也就是你要算 $\frac{\frac{n!}{p^{p_1}}}{\frac{m!}{p^{p_2}} \times \frac{(n-m)!}{p^{p_3}}} \times p^{p_1-p_2-p_3}$
$p_1,p_2,p_3$ 可以递推算一下
然后在算阶乘的时候其实并不用算第一部分,因为不算第一部分算出来的是 $\frac{n!}{p^{p_1}}$,就不用除了
复杂度大概是 $O(plogp)$

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
int x = 0, f = 1;
char ch;
for (ch = getchar(); !isdigit(ch); ch = getchar())
if (ch == '-')
f = -f;
for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
return x * f;
}
const int mod = 1e9, maxn = 2e6 + 10;
LL a, b;
int pp, k2, k5, fac2[maxn], fac5[maxn];
inline int ksm(int x, LL t, int md) {
int res = 1;
while (t) {
if (t & 1)
res = 1LL * res * x % md;
x = 1LL * x * x % md;
t = t >> 1;
}
return res;
}
inline void exgcd(LL a, LL b, LL &x, LL &y) {
if(!b) {
x = 1, y = 0;
return;
}
exgcd(b, a%b, y, x);
y -= a / b * x;
}
LL x, y;
inline LL inv(LL a, LL md) {
x = 0, y = 0;
exgcd(a, md, x, y);
return (x + md) % md;
}
void print(int ans) {
// cout << pp << " " << ans << endl;
int md = pow(10, pp);
ans %= md;
if (pp == 1)
printf("%01d", ans);
if (pp == 2)
printf("%02d", ans);
if (pp == 3)
printf("%03d", ans);
if (pp == 4)
printf("%04d", ans);
if (pp == 5)
printf("%05d", ans);
if (pp == 6)
printf("%06d", ans);
if (pp == 7)
printf("%07d", ans);
if (pp == 8)
printf("%08d", ans);
if (pp == 9)
printf("%09d", ans);
cout << endl;
}
LL fc1(LL n, int type) {
LL ans = 0, p = type ? 2 : 5;
for (LL i = n; i; i /= p) ans += i / p;
return ans;
}
LL fc2(LL n, int type) {
if(!n) return 1;
int md = type ? k2 : k5;
int s = type ? fac2[md] : fac5[md];
s = ksm(s, n / md, md);
s = 1LL * s * (type ? fac2[n % md] : fac5[n % md]) % md;
return s * fc2(n / (type ? 2 : 5), type) % md;
}
int aa, bb;
LL tms, cur, ret;
int C(LL n, LL m, int type, int div) {
int md = type ? k2 : k5;
if (n < m)
return 0;
tms = fc1(n, type) - fc1(m, type) - fc1(n - m, type);
if (div && type) tms--;
cur = ksm((type ? 2 : 5), tms, md);
if(div && !type)cur = cur * inv(2, md);
if (tms >= 9) return 0;
ret = fc2(n, type) * inv(fc2(m, type), md) % md * inv(fc2(n - m, type), md) % md * cur % md;
return ret;
}
int getC(LL n, LL m, int div) {
int ans = 0;
aa = C(n, m, 1, div), bb = C(n, m, 0, div);
aa = aa * (mod/k2) %mod * inv(mod/k2, k2) %mod;
ans = (ans + aa) %mod;
bb = bb * (mod/k5) %mod * inv(mod/k5, k5) %mod;
ans = (ans + bb) %mod;
return ans;
}
int main() {
k2 = ksm(2, 9, 1e9);
k5 = ksm(5, 9, 1e9);
fac2[0] = fac5[0] = 1;
rep(i, 1, k2) if (i % 2) fac2[i] = 1LL * fac2[i - 1] * i % k2;
else fac2[i] = fac2[i - 1];
rep(i, 1, k5) if (i % 5) fac5[i] = 1LL * fac5[i - 1] * i % k5;
else fac5[i] = fac5[i - 1];
while (scanf("%lld%lld%d", &a, &b, &pp) == 3) {
int ans = ksm(2, a + b - 1, 1e9);
for (LL i = b + 1; i <= (a + b) / 2; i++) (ans += getC(a + b, i, 0)) %= mod;
if (!((a + b) & 1))
(ans += (mod - getC(a + b, ((a + b) >> 1), 1))) %= mod;
print(ans);
}
}

#include <bits/stdc++.h>
#define LL long long
#define rep(i, s, t) for (register int i = (s), i##end = (t); i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = (s), i##end = (t); i >= i##end; --i)
using namespace std;
inline int read() {
int x = 0, f = 1; char ch;
for (ch = getchar(); !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
for (; isdigit(ch); ch = getchar()) x = 10 * x + ch - '0';
return x * f;
}
LL n, m, p;
inline LL ksm(LL x, LL t, LL mod) {
LL res = 1;
while(t) {
if(t & 1) (res *= x) %= mod;
(x *= x) %= mod;
t = t >> 1;
} return res;
}
inline void exgcd(LL a, LL b, LL &x, LL &y) {
if(!b) {
x = 1, y = 0;
return;
}
exgcd(b, a%b, y, x);
y -= (a / b) * x;
}
inline LL inv(LL a, LL mod) {
LL x, y;
exgcd(a, mod, x, y);
return (x + mod) % mod;
}
#define mp make_pair
pair<LL, LL> a, b;
inline LL fc1(LL n, LL p) {
int ans = 0;
for(LL i = n; i; i /= p) ans += (i / p);
return ans;
}
inline LL fc2(LL n, LL p, LL pr) {
if(!n) return 1;
LL s = 1;
rep(i, 1, pr) if(i % p) s = 1LL * s * i % pr;
s = ksm(s, n / pr, pr);
rep(i, 1, n % pr) if(i % p) s = 1LL * s * i % pr;
return s * fc2(n / p, p, pr) % pr;
}
inline LL C(LL n, LL m, LL p, LL tms) {
LL pr = pow(p, tms), px = fc1(n, p) - fc1(m, p) - fc1(n - m, p);
if(px >= tms) return 0;
LL res = fc2(n, p, pr) * inv(fc2(m, p, pr), pr) % pr * inv(fc2(n - m, p, pr), pr) % pr;
return ksm(p, px, pr) * res % pr;
}
pair<LL, LL> merge(pair<LL, LL> a, pair<LL, LL> b) {
LL t = __gcd(a.second, b.second);
LL gm = b.second / t, M = gm * a.second;
pair<LL, LL> c;
c.first = ((LL) inv(a.second / t, gm) * ((b.first - a.first) / t) % gm * a.second + a.first) % M;
c.second = M; if(c.first < 0) c.first += M;
return c;
}
int main() {
cin >> n >> m >> p;
a = mp(0, 1);
for(LL i=2;i<=p;i++) if(p % i == 0) {
LL tms = 0, cur = 1;
while(p % i == 0) tms++, cur *= i, p /= i;
b = mp(C(n, m, i, tms), cur);
a = merge(a, b);
}
cout << a.first << endl;
}
代码暂时没拿到,先咕,明天补
我卢本伟没有咕咕
来源:https://www.cnblogs.com/Kong-Ruo/p/10526964.html
