# A. 数正方体
推了 2.5h 没有推出来,心态非常崩。
主要是没有网通项式方面去想,考场上推出来递推式之后一直在优化递推……
通过手模不难发现,.
然后再打一个更大的表,不难发现
然后 预处理, 查询就好了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
T = read(), init(N - 10);
while(T--) solve();
return 0;
}
# B. 数连通块
首先把题目中的树跑出来,设 表示 点存在的概率, 表示 点不存在的概率。
对于询问 ,考虑每个点对连通块个数的贡献。
设当前点为 ,分类讨论:
-
在 中, 想要对答案有贡献,那么必须 不存在,且 存在,所以贡献为 。
-
不在 中,只要 存在就对答案就贡献,所以贡献为 。
暴力是 的,期望得分 ,考虑使用莫队优化,然后就可以过了……
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
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. 数字符串
暴力 没什么好说的了,可以得 。
观察题目条件 ,我们开个桶记录合法的 个数就好, 就可以直接算出来了。
考虑在失配树上跑,开个栈记录一条从上到下的链。因为是失配树,所以父亲是儿子的 ,也就是满足条件②。
对于条件③,记录 表示 到祖先的链上最远的合法的位置,具体怎么维护看代码吧。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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(){
freopen("test.in", "r", stdin);
freopen("test.out", "w", stdout);
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;
}