当前位置:网站首页>[ACNOI2022]做过也不会
[ACNOI2022]做过也不会
2022-06-24 06:56:00 【OneInDark】
题目
题目背景
卷爷的刀已经抵在喉头;寒光一闪;我看到鲜血飞溅。我的身体不受控制地坠向地面……
我从现实中惊醒。“幸好在梦世界里不会发生这样的事。” 我长吁一口气。
题目描述
求 n × n n\times n n×n 矩阵 A A A 的行列式,其中
A i , j = { 1 ( i = j ) 0 ( i ≠ j ∧ i ∣ j ) C ( otherwise ) A_{i,j}=\begin{cases}1 & (i=j)\\0 & (i\ne j\land i\mid j)\\ C & (\text{otherwise}) \end{cases} Ai,j=⎩⎪⎨⎪⎧10C(i=j)(i=j∧i∣j)(otherwise)
对 998244353 998244353 998244353 取模。
数据范围与提示
n ⩽ 1 0 11 n\leqslant 10^{11} n⩽1011 。时限 6 s \rm 6s 6s 。
思路
简单推导 det \det det 的方式:下一行减去上一行,变成海森堡矩阵。
复杂方法:将对角线上 1 1 1 视作 C + ( 1 − C ) C+(1-C) C+(1−C),枚举哪些位置选择了 ( 1 − C ) (1-C) (1−C),则剩余部分是主子式。
引理:当且仅当主子式保留的行列编号 { x i } \{x_i\} { xi} 满足 x 1 ∣ x 2 ∣ x 3 ∣ ⋯ ∣ x k x_1\mid x_2\mid x_3\mid\cdots\mid x_k x1∣x2∣x3∣⋯∣xk 时,其 d e t \rm det det 是 C k C^k Ck,否则是 0 0 0 。
证明:每一行都只有一个真后缀为全零,其余是 C C C 。所以必为下三角矩阵,此时两两之间有倍数关系。
由此,我们对没选择的行列编号进行 d p \tt dp dp,可以很容易地写出转移
f ( n ) = C ( 1 − C ) n − 1 + ∑ d ∣ n f ( d ) ( 1 − C ) n − d − 1 C f(n)=C(1-C)^{n-1}+\sum_{d\mid n}f(d)(1-C)^{n-d-1}C f(n)=C(1−C)n−1+d∣n∑f(d)(1−C)n−d−1C
以及
a n s = ( 1 − C ) n + ∑ i = 1 n f ( i ) ( 1 − C ) n − i ans=(1-C)^n+\sum_{i=1}^{n}f(i)(1-C)^{n-i} ans=(1−C)n+i=1∑nf(i)(1−C)n−i
稍微变形一下
f ( n ) ( 1 − C ) − n = C 1 − C + ∑ d ∣ n C 1 − C ( f ( d ) ( 1 − C ) − d ) f(n)(1-C)^{-n}=\frac{C}{1-C}+\sum_{d\mid n}\frac{C}{1-C}(f(d)(1-C)^{-d}) f(n)(1−C)−n=1−CC+d∣n∑1−CC(f(d)(1−C)−d)
简记 v : = C 1 − C v:=\frac{C}{1-C} v:=1−CC,不妨设 C ≠ 1 C\ne 1 C=1 。并记 g ( n ) : = f ( n ) ( 1 − C ) − n g(n):=f(n)(1-C)^{-n} g(n):=f(n)(1−C)−n 。
g ( n ) = v + ∑ d ∣ n d ≠ n v ⋅ g ( d ) (1) g(n)=v+\sum_{d\mid n}^{d\ne n}v\cdot g(d)\tag{1} g(n)=v+d∣n∑d=nv⋅g(d)(1)
a n s = ( 1 − C ) n ∑ i = 1 n g ( i ) ans=(1-C)^n\sum_{i=1}^{n}g(i) ans=(1−C)ni=1∑ng(i)
注意到 g ( i ) g(i) g(i) 不是积性函数,我开始脑抽,打算写出关于质因子指数的 g ( i ) g(i) g(i) 的表达式。
脑抽中
设 n = ∏ p i t i n=\prod p_i^{t_i} n=∏piti,记
λ l : = ∏ ( l − 1 + t i t i ) \lambda_l:=\prod{l-1+t_i\choose t_i} λl:=∏(til−1+ti)
即单个质因子的指数下降方案,在长为 l l l 的链上。容斥以确保每一步着实有下降。
α l : = ∑ i = 0 l − 1 ( l − 1 i ) ( − 1 ) i λ l − i \alpha_l:=\sum_{i=0}^{l-1}{l-1\choose i}(-1)^i\lambda_{l-i} αl:=i=0∑l−1(il−1)(−1)iλl−i
g ( n ) = ∑ i = 1 log n α i v i = ∑ i = 1 log n v i ∑ j = 0 i − 1 ( i − 1 j ) ( − 1 ) j λ i − j = ∑ i = 1 log n v i ∑ j = 0 i − 1 ( i − 1 j ) ( − 1 ) j ∏ ( i − j − 1 + t k t k ) = ∑ l ( ∑ i = l + 1 log n v i ( i − 1 i − l − 1 ) ( − 1 ) i − l − 1 ) ∏ ( l + t k t k ) = ∑ l β l ⋅ I l + 1 ( n ) \begin{aligned} g(n)&=\sum_{i=1}^{\log n}\alpha_iv^i=\sum_{i=1}^{\log n}v^i\sum_{j=0}^{i-1}{i-1\choose j}(-1)^j\lambda_{i-j}\\ &=\sum_{i=1}^{\log n}v^i\sum_{j=0}^{i-1}\binom{i-1}{j}(-1)^j\prod{i-j-1+t_k\choose t_k}\\ &=\sum_{l}\left(\sum_{i=l+1}^{\log n}v^i{i-1\choose i-l-1}(-1)^{i-l-1}\right)\prod{l+t_k\choose t_k}\\ &=\sum_{l}\beta_l\cdot I^{l+1}(n) \end{aligned} g(n)=i=1∑lognαivi=i=1∑lognvij=0∑i−1(ji−1)(−1)jλi−j=i=1∑lognvij=0∑i−1(ji−1)(−1)j∏(tki−j−1+tk)=l∑(i=l+1∑lognvi(i−l−1i−1)(−1)i−l−1)∏(tkl+tk)=l∑βl⋅Il+1(n)
I l + 1 I^{l+1} Il+1 指 ( l + 1 ) (l{+}1) (l+1) 个 I I I 的狄利克雷卷积的结果。于是可以 O ( log n ) \mathcal O(\log n) O(logn) 次筛法解决,比如杜教筛或 min25 \texttt{min25} min25 。
正解
杜教筛不基于积性函数。而且,“因子的值求和” 不像狄利克雷卷积吗?这不像分治 FTT \textit{FTT} FTT 吗?
事实上, ( 1 ) (1) (1) 式两边同时求前缀和立刻有
⇒ S ( n ) = v n + ∑ i = 2 n v ⋅ S ( ⌊ n / i ⌋ ) \Rightarrow S(n)=vn+\sum_{i=2}^{n}v\cdot S(\lfloor n/i\rfloor) ⇒S(n)=vn+i=2∑nv⋅S(⌊n/i⌋)
其中 S ( n ) = ∑ i ⩽ n g ( i ) S(n)=\sum_{i\leqslant n}g(i) S(n)=∑i⩽ng(i) 。于是杜教筛吧。时间复杂度 O ( n 2 / 3 ) \mathcal O(n^{2/3}) O(n2/3) 的……吗?
注意非积性函数不能做严格意义上的线性筛。需优化。事实上,质因数的指数的可重集相同时, g g g 的值显然相同。因此我们只有很少的值需要枚举因子。但是怎么找到对应关系呢?
一个方法是 hash \texttt{hash} hash 。当然我们也可以魔改线性筛,每个数记录其最大质因子和次数,并预处理每个质数的幂。然后存 f i f_i fi 为,与 i i i 拥有相同的指数可重集的数中,最小的一个。直接求 f i f_i fi 麻烦,可以求 j j j 使得 f i = f j f_i=f_j fi=fj 。设 i i i 移除最大质因子后得到 u u u,若 f u ≠ u f_u\ne u fu=u 则 j = i u f u j=\frac{i}{u}f_u j=uifu,否则再做指数与质因数编号的判断。
最终只有 500 + 500+ 500+ 个数需暴力计算,所以复杂度总算是 O ( n 2 / 3 ) \mathcal O(n^{2/3}) O(n2/3) 了。
代码
#include <cstdio>
#include <algorithm> // Almighty XJX yyds!!
#include <cstring> // oracle: ZXY yydBUS!!!
#include <cctype> // I hate rainybunny.
using llong = long long;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
# define rep0(i,a,b) for(int i=(a); i!=(b); ++i)
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar()) if(c == '-') f = -f;
for(; isdigit(c); c=getchar()) a = a*10+(c^48);
return a*f;
}
const int LOGN = 40, MOD = 998244353;
inline llong qkpow(llong b, int q){
llong a = 1;
for(; q; q>>=1,b=b*b%MOD) if(q&1) a = a*b%MOD;
return a;
}
const int MAXN = 23544347;
bool isPrime[MAXN]; int* ppow[MAXN];
int primes[MAXN], primes_size, g[MAXN];
int fa[MAXN], big[MAXN], num[MAXN], nxt[MAXN], cnt[MAXN];
void dfs(int &res, int x, int y){
if(x == 1){
if(g+y != &res){
res = (res+g[y])%MOD; } return; }
rep(i,0,num[x]) dfs(res,nxt[x],y), y *= big[x];
}
void sieve(const int &v, int n = MAXN-1){
memset(isPrime+2, true, n-1);
fa[1] = 1, g[1] = v;
for(int i=2,&len=primes_size; i<=n; ++i){
if(isPrime[i]){
primes[++len] = big[i] = i, cnt[i] = 1;
num[i] = 1, fa[i] = 2, nxt[i] = 1;
g[i] = int(llong(v+1)*v%MOD);
for(int j=2,p=i; true; ++j,p*=i)
if(p > n/i){
ppow[i] = new int[j]; break; }
for(int j=0,p=1; p<=n/i; ++j,p*=i,ppow[i][j]=p);
}
else{
const int rt = fa[nxt[i]];
if(rt != nxt[i]) g[i] = g[fa[i] = fa[rt*(i/nxt[i])]];
else if(big[i] != primes[cnt[rt]+1]){
// not nearest
fa[i] = rt*ppow[primes[cnt[rt]+1]][num[i]];
fa[i] = fa[fa[i]], g[i] = g[fa[i]];
}
else if(rt != 1 && num[rt] < num[i]){
fa[i] = nxt[rt]*ppow[big[rt]][num[i]]
*ppow[big[i]][num[rt]]; // switch
fa[i] = fa[fa[i]], g[i] = g[fa[i]];
}
else{
// I am smallest
static int wxk = 0; ++ wxk;
fa[i] = i, dfs(g[i],i,1);
g[i] = int(llong(g[i]+1)*v%MOD);
}
}
for(int j=1; j<=len; ++j){
const int to = i*primes[j]; if(to > n) break;
isPrime[to] = false, big[to] = big[i];
if(!(i%primes[j])){
if(nxt[i] == 1) num[to] = num[i]+1, nxt[to] = 1;
else num[to] = num[i], nxt[to] = nxt[i]*primes[j];
cnt[to] = cnt[i]; break;
}
num[to] = num[i], nxt[to] = nxt[i]*primes[j], cnt[to] = cnt[i]+1;
}
}
}
int res[4650];
int getSum(const llong &n, const int &v, llong x){
if(x < MAXN) return g[x];
int &w = res[n/x]; if(~w) return w;
w = int(x%MOD); // easiest
for(llong l=2,r,val; l!=x+1; l=r){
val = x/l, r = x/val+1; // move
w = int((w+(r-l)%MOD*getSum(n,v,val))%MOD);
}
return w = int(llong(w)*v%MOD);
}
int main(){
llong n; scanf("%lld",&n); int c = readint();
if(c == 1){
puts(n <= 2 ? "1" : "0"); return 0; }
int v = int(c*qkpow(1-c+MOD,MOD-2)%MOD);
sieve(v); rep0(i,2,MAXN) g[i] = (g[i]+g[i-1])%MOD;
memset(res, -1, sizeof(res));
int ans = getSum(n,v,n)+1;
ans = int(ans*qkpow(1+MOD-c,int(n%(MOD-1)))%MOD);
printf("%d\n",ans);
return 0;
}
边栏推荐
- [data update] Xunwei comprehensively upgraded NPU development data based on 3568 development board
- 工控机防破解
- Model effect optimization, try a variety of cross validation methods (system operation)
- 直播回顾 | 云原生混部系统 Koordinator 架构详解(附完整PPT)
- 模型效果优化,试一下多种交叉验证的方法(系统实操)
- 蓝桥杯_N 皇后问题
- C语言_字符串与指针的爱恨情仇
- Pipeline concept of graphic technology
- Swift Extension NetworkUtil(網絡監聽)(源碼)
- Synchronous FIFO
猜你喜欢

SVN实测常用操作-记录操作大全

Hilbert Huang Transform

OC Extension 检测手机是否安装某个App(源码)

Gossip: what happened to 3aC?

Application of JDBC in performance test

Examples of corpus data processing cases (reading multiple text files, reading multiple files specified under a folder, decoding errors, reading multiple subfolder text, batch renaming of multiple fil

首次曝光 唯一全域最高等级背后的阿里云云原生安全全景图

没有专业背景,还有机会成为机器学习工程师吗?

疫情下更合适的开发模式

Solve the problem of notebook keyboard disabling failure
随机推荐
Atguigu---16-custom instruction
decltype用法介绍
transformers PreTrainedTokenizer类
Solution to the error of running NPM run eject
解决错误: LNK2019 无法解析的外部符号
Dart development server, do I have a fever?
Synchronous FIFO
C# Lambda
Getting started with crawler to giving up 06: crawler play Fund (with code)
[C language] system date & time
L1-019 who goes first (15 points)
研究生英语期末考试复习
Swift Extension NetworkUtil(網絡監聽)(源碼)
Installation and use of selenium IDE
JS implementation to check whether an array object contains values from another array object
Decltype usage introduction
[测试开发]初识软件测试
对于flex:1的详细解释,flex:1
Introduction of model compression tool based on distiller
Smart pointer remarks