# A. 数正方体
推了 2.5h 没有推出来,心态非常崩。
主要是没有网通项式方面去想,考场上推出来递推式之后一直在优化递推……
通过手模不难发现,.
然后再打一个更大的表,不难发现
然后 预处理, 查询就好了。
#include <bits/stdc++.h> | |
#define pb push_back | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0, f = 1; | |
char ch = getchar(); | |
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x * f; | |
} | |
template <typename T> inline void write(T x){ | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 1e5 + 10; | |
const int M = 1e4 + 10; | |
const int mod = 998244353; | |
int T, n, m; | |
inline int add(int x) {return x >= mod ? x - mod : x;} | |
inline int sub(int x) {return x < 0 ? x + mod : x;} | |
inline int mul(int x, int y) {return 1ll * x * y % mod;} | |
int fac[N], ifac[N]; | |
inline int qpow(int a, int b){ | |
int res = 1; | |
while(b){ | |
if(b & 1) res = mul(res, a); | |
a = mul(a, a), b >>= 1; | |
} | |
return res; | |
} | |
inline void init(int n){ | |
fac[0] = 1; | |
for(int i = 1; i <= n; ++i) fac[i] = mul(fac[i - 1], i); | |
ifac[n] = qpow(fac[n], mod - 2); | |
for(int i = n - 1; i >= 0; --i) ifac[i] = mul(ifac[i + 1], i + 1); | |
} | |
inline int C(int n, int m){ | |
return mul(fac[n], mul(ifac[m], ifac[n - m])); | |
} | |
inline void solve(){ | |
n = read(), m = read(); | |
write(mul(C(n, m), qpow(2, n - m))), puts(""); | |
} | |
signed main(){ | |
#ifndef ONLINE_JUDGE | |
freopen("test.in", "r", stdin); | |
freopen("test.out", "w", stdout); | |
#endif | |
T = read(), init(N - 10); | |
while(T--) solve(); | |
return 0; | |
} |
# B. 数连通块
首先把题目中的树跑出来,设 表示 点存在的概率, 表示 点不存在的概率。
对于询问 ,考虑每个点对连通块个数的贡献。
设当前点为 ,分类讨论:
在 中, 想要对答案有贡献,那么必须 不存在,且 存在,所以贡献为 。
不在 中,只要 存在就对答案就贡献,所以贡献为 。
暴力是 的,期望得分 ,考虑使用莫队优化,然后就可以过了……
#include <bits/stdc++.h> | |
#define pb push_back | |
#define be(x) x / B | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0, f = 1; | |
char ch = getchar(); | |
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x * f; | |
} | |
template <typename T> inline void write(T x){ | |
if(x < 0) putchar('-'), x = -x; | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 1e5 + 10; | |
const int mod = 1e9 + 7; | |
int n, m, Q, B; | |
int p[N], q[N]; | |
vector <int> g[N]; | |
inline int add(int x, int y) {return x + y >= mod ? x + y - mod : x + y;} | |
inline int sub(int x) {return x < 0 ? x + mod : x;} | |
inline int mul(int x, int y) {return 1ll * x * y % mod;} | |
inline int qpow(int a, int b){ | |
int res = 1; | |
while(b){ | |
if(b & 1) res = mul(res, a); | |
a = mul(a, a), b >>= 1; | |
} | |
return res; | |
} | |
inline int inv(int a) {return qpow(a, mod - 2);} | |
int fa[N]; | |
inline void dfs(int x, int f){ | |
fa[x] = f; | |
for(auto y : g[x]) if(y != f) dfs(y, x); | |
} | |
struct node{ | |
int l, r, id; | |
inline bool operator < (const node &b) const{ | |
return be(l) != be(b.l) ? l < b.l : r < b.r; | |
} | |
}a[N]; | |
int ans[N], s[N]; | |
int l, r, res; | |
inline void add(int x){ | |
if(fa[x] >= l && fa[x] <= r) res = add(res, mul(p[x], q[fa[x]])); | |
else res = add(res, p[x]); | |
s[fa[x]] = add(s[fa[x]], p[x]), res = add(sub(res - s[x]), mul(s[x], q[x])); | |
} | |
inline void del(int x){ | |
if(fa[x] >= l && fa[x] <= r) res = sub(res - mul(p[x], q[fa[x]])); | |
else res = sub(res - p[x]); | |
s[fa[x]] = sub(s[fa[x]] - p[x]), res = add(sub(res - mul(s[x], q[x])), s[x]); | |
} | |
signed main(){ | |
#ifndef ONLINE_JUDGE | |
freopen("test.in", "r", stdin); | |
freopen("test.out", "w", stdout); | |
#endif | |
n = read(), m = read(), Q = read(), B = sqrt(n); | |
for(int i = 1, a, b; i <= n; ++i) | |
a = read(), b = read(), p[i] = mul(a, inv(b)), q[i] = sub(1 - p[i]); | |
for(int i = 1; i <= m; ++i){ | |
int u = read(), v = read(); | |
g[u].pb(v), g[v].pb(u); | |
} | |
dfs(1, 0); | |
for(int i = 1; i <= Q; ++i) a[i] = (node){read(), read(), i}; | |
sort(a + 1, a + 1 + Q); | |
l = 1, r = 0; | |
for(int i = 1; i <= Q; ++i){ | |
while(l > a[i].l) add(--l); | |
while(r < a[i].r) add(++r); | |
while(l < a[i].l) del(l++); | |
while(r > a[i].r) del(r--); | |
ans[a[i].id] = res; | |
} | |
for(int i = 1; i <= Q; ++i) write(ans[i]), puts(""); | |
return 0; | |
} |
# C. 数大模拟
拿了暴力分跑路了 /kk
正解现在还不会,先咕了。
# D. 数字符串
暴力 没什么好说的了,可以得 。
观察题目条件 ,我们开个桶记录合法的 个数就好, 就可以直接算出来了。
考虑在失配树上跑,开个栈记录一条从上到下的链。因为是失配树,所以父亲是儿子的 ,也就是满足条件②。
对于条件③,记录 表示 到祖先的链上最远的合法的位置,具体怎么维护看代码吧。
#include <bits/stdc++.h> | |
#define pb push_back | |
using namespace std; | |
namespace IO{ | |
inline int read(){ | |
int x = 0, f = 1; | |
char ch = getchar(); | |
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();} | |
while(isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = getchar(); | |
return x * f; | |
} | |
template <typename T> inline void write(T x){ | |
if(x < 0) putchar('-'), x = -x; | |
if(x > 9) write(x / 10); | |
putchar(x % 10 + '0'); | |
} | |
} | |
using namespace IO; | |
const int N = 1e6 + 10; | |
const int mod = 998244353; | |
char s[N]; | |
int n, k, ans = 1; | |
int nxt[N]; | |
vector <int> g[N]; | |
int stk[N], top, buk[N], p[N], f[N]; | |
inline void dfs(int x, int fa){ | |
if(x) stk[++top] = x, buk[2 * x % k]++; | |
p[x] = p[fa]; | |
while(p[x] < top && 2 * stk[p[x] + 1] < x + 1) p[x]++, buk[2 * stk[p[x]] % k]--; | |
f[x] = buk[x % k]; | |
for(auto y : g[x]) dfs(y, x); | |
while(p[x] > p[fa]) buk[2 * stk[p[x]] % k]++, p[x]--; | |
if(x) top--, buk[2 * x % k]--; | |
} | |
signed main(){ | |
#ifndef ONLINE_JUDGE | |
freopen("test.in", "r", stdin); | |
freopen("test.out", "w", stdout); | |
#endif | |
scanf("%s", s + 1), k = read(); | |
n = strlen(s + 1); | |
for(int i = 2, j = 0; i <= n; ++i){ | |
while(j && s[i] != s[j + 1]) j = nxt[j]; | |
if(s[i] == s[j + 1]) j++; | |
nxt[i] = j; | |
} | |
for(int i = 1; i <= n; ++i) g[nxt[i]].pb(i); | |
dfs(0, 0); | |
for(int i = 1; i <= n; ++i) ans = 1ll * ans * (f[i] + 1) % mod; | |
write(ans), puts(""); | |
return 0; | |
} |