CF997C Sky Full of Stars
求 n × n n\times n n×n的网格内每个格子染三种颜色,其中至少有一行或一列是同一种颜色的方案数。
转化为求没有一行或一列颜色相同。
直接枚举相同的行列数进行容斥:
=
3
∑
i
=
0
n
(
n
i
)
(
−
1
)
i
∑
j
=
0
n
(
n
j
)
(
−
1
)
j
3
(
n
−
i
)
(
n
−
j
)
+
2
∑
i
=
1
n
(
n
i
)
(
−
1
)
i
3
n
(
n
−
i
)
(
3
i
−
3
)
−
2
×
3
n
2
=
3
∑
i
=
0
n
(
n
i
)
(
−
1
)
i
(
3
n
−
i
−
1
)
n
+
2
∑
i
=
1
n
(
n
i
)
(
−
1
)
i
3
n
(
n
−
i
)
(
3
i
−
3
)
−
2
×
3
n
2
\begin{aligned}&=3\sum_{i=0}^n \binom ni(-1)^i \sum_{j=0}^n \binom nj(-1)^j 3^{(n-i)(n-j)} + 2\sum_{i=1}^n \binom ni(-1)^i 3^{n(n-i)}(3^i-3) - 2\times 3^{n^2} \\ &=3 \sum_{i=0}^n \binom ni (-1)^i (3^{n-i}-1)^n+ 2\sum_{i=1}^n \binom ni(-1)^i 3^{n(n-i)}(3^i-3) - 2 \times 3^{n^2}\end{aligned}
=3i=0∑n(in)(−1)ij=0∑n(jn)(−1)j3(n−i)(n−j)+2i=1∑n(in)(−1)i3n(n−i)(3i−3)−2×3n2=3i=0∑n(in)(−1)i(3n−i−1)n+2i=1∑n(in)(−1)i3n(n−i)(3i−3)−2×3n2
后面的那个式子是因为
i
i
i和
j
j
j有一个为
0
0
0的时候相同的染色行列不一定只有三种方案。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
using namespace std;
int n;
int Pow(int b,LL k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
int main(){
scanf("%d",&n);
int ans = 3ll * Pow(3,n*1ll*n) % mod , C = 1;
rep(i,0,n){
ans = (ans - 3ll * C * (i&1 ? -1ll : 1ll) * Pow(Pow(3,n-i)-1,n)) % mod;
if(i) ans = (ans - 2ll * C * (i&1 ? -1ll : 1ll) * Pow(3,1ll*n*(n-i)) % mod * (Pow(3,i) - 3)) % mod;
C = 1ll * C * (n-i) % mod * Pow(i+1,mod-2) % mod;
}
printf("%d\n",(ans+mod)%mod);
}
[AGC035F] Two Histograms
可以发现一个网格对应多个方案,当且仅当存在
l
x
=
y
,
k
y
=
x
−
1
l_x = y , k_y = x-1
lx=y,ky=x−1,这时让
l
x
=
y
−
1
,
k
y
=
x
l_x=y-1,k_y=x
lx=y−1,ky=x也可以得到同样的网格。
所以我们设
l
x
=
y
,
k
y
=
x
−
1
l_x = y , k_y = x-1
lx=y,ky=x−1为
k
y
k_y
ky不合法,容斥求出所有的合法方案即为本质不同的网格方案(即我们只在所有可以有多个方案的网格只计算
l
x
=
y
−
1
,
k
y
=
x
l_x=y-1,k_y=x
lx=y−1,ky=x这一种情况。)。
a
n
s
=
∑
i
=
0
min
(
n
,
m
)
(
n
i
)
(
−
1
)
i
(
m
i
)
i
!
(
m
+
1
)
n
−
i
(
n
+
1
)
m
−
i
ans = \sum_{i=0}^{\min(n,m)} \binom ni (-1)^i\binom mi i! (m+1)^{n-i}(n+1)^{m-i}
ans=i=0∑min(n,m)(in)(−1)i(im)i!(m+1)n−i(n+1)m−i
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
#define LL long long
using namespace std;
int n,m;
int Pow(int b,LL k){ int r=1;for(;k;k>>=1,b=1ll*b*b%mod) if(k&1) r=1ll*r*b%mod;return r; }
int main(){
scanf("%d%d",&n,&m);
int Cn=1,Cm=1,ans=0,fc=1;
rep(i,0,min(n,m)){
ans = (ans + 1ll * Cn * Cm % mod * (i&1 ? -1ll : 1ll) * fc % mod * Pow(m+1,n-i) % mod * Pow(n+1,m-i)) % mod;
Cn = 1ll * Cn * (n-i) % mod * Pow(i+1 , mod-2) % mod;
Cm = 1ll * Cm * (m-i) % mod * Pow(i+1 , mod-2) % mod;
fc = 1ll * fc * (i+1) % mod;
}
printf("%d\n",(ans+mod)%mod);
}
LOJ #6181. 某个套路求和题
f
(
n
)
f(n)
f(n)在质数处为
−
1
-1
−1,有平方因子数处为
0
0
0,其他时候为
1
1
1。
所以答案等于
∑
i
=
1
μ
(
i
)
⌊
n
i
2
⌋
−
2
π
(
n
)
\sum_{i=1}\mu(i) \left\lfloor\frac {n}{i^2}\right\rfloor-2 \pi(n)
i=1∑μ(i)⌊i2n⌋−2π(n)
前者直接算,后者
M
i
n
2
5
Min_25
Min25。
写了一个很麻烦的实现:
#include<bits/stdc++.h>
#define maxn 200005
#define LL long long
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
LL n,sn,a[maxn],s[maxn],mu[maxn];
double inv[maxn];
int cnt;
int ID(LL a){ return a <= sn ? a : cnt - n/a + 1; }
int main(){
scanf("%lld",&n);
sn = sqrt(n);
for(LL i=1;i<=n;i++) a[++cnt] = (i = n / (n / i)) , s[cnt] = i - 1;
for(LL i=2;i<=sn;i++){
inv[i] = 1.0 / i;
if(s[i] ^ s[i-1]) for(LL j=cnt,LIM=i*i;a[j]>=LIM;j--)
s[j] -= s[ID((LL)(a[j] * inv[i] + 1e-9))] - s[i-1];
}
for(int i=1;i<=cnt;i++) mu[i] = -s[i];
for(LL i=sn;i>=2;i--) if(s[i] ^ s[i-1]) for(LL j=cnt,LIM=i*i;a[j]>=LIM;j--)
mu[j] -= mu[ID((LL)(a[j] * inv[i] + 1e-9))] + s[i];
for(int i=sn;i>=1;i--) mu[i] -= mu[i-1];
mu[1] = 1;
LL ans = - 2 * s[cnt];
for(int i=1;i<=sn;i++) ans += mu[i] * (n / i / i);
printf("%lld\n",(ans%mod+mod)%mod);
}
#528. 「LibreOJ β Round #4」求和
∑ i = 1 n ∑ j = 1 m μ 2 ( gcd ( i , j ) ) = ∑ d = 1 min ( n , m ) μ 2 ( d ) ∑ i = 1 n d ∑ j = 1 m d [ gcd ( i , j ) = 1 ] = ∑ d = 1 min ( n , m ) μ 2 ( d ) ∑ p = 1 min ( n , m ) d μ ( p ) ⌊ n d p ⌋ ⌊ m d p ⌋ = ∑ D = 1 min n , m ⌊ n d ⌋ ⌊ m d ⌋ ∑ d ∣ D μ 2 ( d ) μ ( D d ) \begin{aligned}&\sum_{i=1}^n \sum_{j=1}^m \mu^2(\gcd(i,j)) = \sum_{d=1}^{\min(n,m)} \mu^2(d)\sum_{i=1}^{\frac nd}\sum_{j=1}^{\frac md} [\gcd(i,j)=1]\\&=\sum_{d=1}^{\min(n,m)} \mu^2(d)\sum_{p=1}^{\frac {\min(n,m)}{d}} \mu(p)\lfloor \frac {n}{dp}\rfloor\lfloor \frac {m}{dp} \rfloor \\&=\sum_{D=1}^{\min n,m} \lfloor\frac nd\rfloor\lfloor\frac md\rfloor\sum_{d|D} \mu^2(d)\mu(\frac Dd)\end{aligned} i=1∑nj=1∑mμ2(gcd(i,j))=d=1∑min(n,m)μ2(d)i=1∑dnj=1∑dm[gcd(i,j)=1]=d=1∑min(n,m)μ2(d)p=1∑dmin(n,m)μ(p)⌊dpn⌋⌊dpm⌋=D=1∑minn,m⌊dn⌋⌊dm⌋d∣D∑μ2(d)μ(dD)
考虑
∑
d
∣
D
μ
2
(
d
)
μ
(
D
d
)
\sum_{d|D} \mu^2(d)\mu(\frac Dd)
∑d∣Dμ2(d)μ(dD),这是个积性函数,我们考虑质数的次方处的值,可以发现这个函数在
p
1
,
p
3
,
p
4
.
.
.
p
c
,
c
≠
2
p^1,p^3,p^4...p^c,c\neq 2
p1,p3,p4...pc,c=2处都为
0
0
0。
而在
p
2
p^2
p2处为
μ
(
p
)
\mu(p)
μ(p),所以
∑
d
∣
D
μ
2
(
d
)
μ
(
D
d
)
=
[
x
2
=
D
]
μ
(
x
)
\sum_{d|D} \mu^2(d)\mu(\frac Dd) = [x^2 = D]\mu(x)
∑d∣Dμ2(d)μ(dD)=[x2=D]μ(x)其中
x
=
⌊
D
⌋
x = \lfloor\sqrt D \rfloor
x=⌊D⌋。
所以预处理
≤
n
\leq \sqrt n
≤n的
μ
\mu
μ的前缀和即可整除优化。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 5000007
#define LL long long
#define mod 998244353
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
LL n,m;
int mu[maxn],pr[maxn],vis[maxn],cnt_pr;
int main(){
scanf("%lld%lld",&n,&m);
if(n > m) swap(n,m);
mu[1]=1;
int sn = sqrt(n);
rep(i,2,sn){
if(!vis[i]) pr[cnt_pr++] = i , mu[i] = -1;
for(int j=0;pr[j] * i <= sn;j++){
vis[i * pr[j]] = 1;
if(i % pr[j] == 0){
mu[i * pr[j]] = 0;
break;
}
mu[i * pr[j]] = -mu[i];
}
mu[i] += mu[i-1];
}
int ans = 0;
for(LL i=1,nxt;i<=n;i=nxt+1){
nxt = min(n / (n / i) , m / (m / i));
ans = (ans + 1ll * (n / i) % mod * (m / i % mod) % mod * (mu[(int)(sqrt(nxt)+1e-9)] - mu[(int)(sqrt(i-1)+1e-9)])) % mod;
}
printf("%d\n",(ans+mod)%mod);
}
LOJ #6244. 七选五
考虑一个固定的排列 a a a,大小为 r r r,现在你要选出 n n n的 r r r排列,求这个排列和 a a a中恰好有 x x x相等的方案数。
广义容斥原理模板题:
广义容斥原理:
设
β
(
x
)
\beta (x)
β(x)为钦定
x
x
x个条件满足的方案数。
则恰好有
x
x
x个方案满足的方案数
f
(
x
)
=
∑
i
=
x
n
(
−
1
)
i
−
x
β
(
i
)
(
i
x
)
f(x) = \sum_{i=x}^n (-1)^{i-x}\beta(i)\binom {i}{x}
f(x)=∑i=xn(−1)i−xβ(i)(xi)
容斥系数为
(
−
1
)
i
−
x
(
i
x
)
(-1)^{i-x}\binom ix
(−1)i−x(xi)是因为
所以对于这题答案
=
∑
i
=
x
r
(
i
x
)
(
−
1
)
i
(
r
i
)
(
n
−
i
r
−
i
)
(
r
−
i
)
!
=\sum_{i=x}^r\binom ix(-1)^i\binom ri \binom {n-i}{r-i}(r-i)!
=i=x∑r(xi)(−1)i(ir)(r−in−i)(r−i)!
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 1000007
#define LL long long
#define mod 1000000007
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
int n,k,x;
int fac[maxn],inv[maxn],invf[maxn];
int C(int n,int m){ return fac[n] * 1ll * invf[m] % mod * invf[n-m] % mod; }
int main(){
fac[0] = fac[1] = inv[0] = inv[1]= invf[0] = invf[1] = 1;
scanf("%d%d%d",&n,&k,&x);
rep(i,2,n) fac[i] = 1ll * fac[i-1] *i % mod, inv[i] = 1ll * (mod - mod /i) * inv[mod % i] % mod,
invf[i] = 1ll * invf[i-1] * inv[i] % mod;
int ans = 0;
rep(i,x,k)
ans = (ans + (i-x&1?-1ll:1ll)*C(i,x)%mod*C(k,i)%mod*fac[n-i]%mod*invf[n-k])%mod;
printf("%d\n",(ans+mod)%mod);
}
[ARC101C] Ribbons on Tree
设
f
i
,
j
f_{i,j}
fi,j表示以
i
i
i为根的子树内剩下
j
j
j个点未匹配的容斥系数和。
则每次可以强行让
i
i
i到父亲的边不被涂色也就是强行匹配剩下的所有点,并乘上一个
−
1
-1
−1的容斥系数。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define maxn 5005
#define LL long long
#define iv2 500000004
#define mod 1000000007
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
int n,f[maxn][maxn],sz[maxn],fac[maxn],pw[maxn],invf[maxn],inv[maxn];
vector<int>G[maxn];
int C2(int x){ return 1ll * x * (x-1) / 2 % mod; }
void dfs(int u,int ff){
int v;f[u][1] = sz[u] = 1;
rep(i,0,G[u].size()-1) if((v=G[u][i])^ff){
dfs(v,u);
static int g[maxn]={};
rep(j,0,sz[u]+sz[v]) g[j] = 0;
rep(j,0,sz[u]) rep(k,0,sz[v]) g[j+k] = (g[j+k] + 1ll * f[u][j] * f[v][k]) % mod;
rep(j,0,sz[u]+sz[v]) f[u][j] = g[j];
sz[u] += sz[v];
}
rep(j,1,sz[u]) if(j%2==0)
f[u][0] = (f[u][0] + f[u][j] * 1ll * fac[j] % mod * pw[j/2] % mod * invf[j/2]) % mod;
if(ff) f[u][0] = -f[u][0];
}
int main(){
scanf("%d",&n);
rep(i,1,n-1){
int u,v;scanf("%d%d",&u,&v);
G[u].push_back(v),G[v].push_back(u);
}
fac[0] = fac[1] = pw[0] = 1 , pw[1] = iv2;
inv[0] = inv[1] = invf[0] = invf[1] = 1;
rep(i,2,n) fac[i] = 1ll * fac[i-1] * i % mod , pw[i] = 1ll * iv2 * pw[i-1] % mod,inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod,
invf[i] = 1ll * invf[i-1] * inv[i] % mod;
dfs(1,0);
printf("%d\n",f[1][0]);
}
LOJ 「美团 CodeM 初赛 Round A」二分图染色
以讹传讹真离谱
将问题转化为棋盘模型,则是同颜色的棋子不能在同一行或同一列,不同颜色的棋子不能在同一个格子里。
设
f
n
f_n
fn为在
n
×
n
n \times n
n×n的棋盘内放置一种颜色的棋子的方案数。
则不同颜色的棋子不能在同一个格子里这个条件可以得到容斥一下
a
n
s
=
∑
i
=
0
(
−
1
)
i
(
n
i
)
2
i
!
f
n
−
i
2
ans = \sum_{i=0} (-1)^i \binom ni^2i!f_{n-i}^2
ans=i=0∑(−1)i(in)2i!fn−i2
对于
f
n
f_n
fn有递推式
f
n
=
2
n
f
n
−
1
−
(
n
−
1
)
2
f
n
−
2
f_n = 2nf_{n-1}-(n-1)^2f_{n-2}
fn=2nfn−1−(n−1)2fn−2
这部分的证明我看到的网上的题解都是错的。
我们可以在
1...
n
−
1
1...n-1
1...n−1选择一列
x
x
x,然后在
n
n
n行
x
x
x列(下面简称
(
n
,
x
)
(n,x)
(n,x))放置一个棋子,同时将之前
f
n
−
1
f_{n-1}
fn−1中对于
n
−
1
n-1
n−1行
n
−
1
n-1
n−1列的方案作出
x
.
.
.
n
−
1
x...n-1
x...n−1列平移到
x
+
1...
n
x+1...n
x+1...n列的操作,这样我们就得到了一个合法方案,同样我们也可以在
1...
n
−
1
1...n-1
1...n−1选择一行
x
x
x然后在
(
x
,
n
)
(x,n)
(x,n)等做类似的操作,也可以直接在
(
n
,
n
)
(n,n)
(n,n)放置一个棋子,同时也可以不放,一共
2
n
2n
2n种操作。
但是发现选择一列和选择一行这两种操作构造出来的棋盘可能会重,如果重了一定是因为
n
n
n行上有一个棋子
n
n
n列上也有一个棋子,并且这两个棋子都不在
(
n
,
n
)
(n,n)
(n,n),所以我们就求出
n
n
n行上有一个棋子,
n
n
n列上有一个棋子的方案数也即
(
n
−
1
)
2
f
n
−
2
(n-1)^2f_{n-2}
(n−1)2fn−2,然后减去即可。
A C C o d e \mathcal AC \ Code AC Code
#include<bits/stdc++.h>
#define mod 1000000007
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define maxn 10000007
using namespace std;
int n,inv[maxn],f[maxn];
int main(){
scanf("%d",&n);
inv[0] = inv[1] = f[0] = 1 , f[1] = 2;
rep(i,2,n) inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod ,
f[i] = (2ll * i * f[i-1] - (i-1ll) * (i-1ll) % mod * f[i-2]) % mod;
int ans = 0 , C = 1;
rep(i,0,n)
ans = (ans + (i&1?-1ll:1ll) * C * f[n-i] % mod * f[n-i]) % mod,
C = 1ll * C * (n-i) % mod * (n-i) % mod * inv[i+1] % mod;
printf("%d\n",(ans+mod)%mod);
}
LOJ #572. 「LibreOJ Round #11」Misaka Network 与求和
求
∑
i
=
1
N
∑
j
=
1
N
f
(
gcd
(
i
,
j
)
)
k
m
o
d
2
32
\sum_{i=1}^{N} \sum_{j=1}^{N} f(\operatorname{gcd}(i, j))^{k} \bmod 2^{32}
∑i=1N∑j=1Nf(gcd(i,j))kmod232。
令
g
(
x
)
=
f
(
x
)
k
g(x) = f(x)^k
g(x)=f(x)k
∑
i
=
1
n
∑
j
=
1
n
g
(
gcd
(
i
,
j
)
)
=
∑
d
=
1
n
g
(
d
)
∑
i
=
1
n
d
∑
j
=
1
n
d
[
(
i
,
j
)
=
1
]
\begin{aligned}&\sum_{i=1}^n\sum_{j=1}^n g(\gcd(i,j))=\sum_{d=1}^n g(d)\sum_{i=1}^\frac nd \sum_{j=1}^{\frac nd} [(i,j)=1]\end{aligned}
i=1∑nj=1∑ng(gcd(i,j))=d=1∑ng(d)i=1∑dnj=1∑dn[(i,j)=1]
因为
g
g
g的定义是次大质因子的
K
K
K次方,次大质因子一定是
m
i
n
2
5
min_25
min25中我们筛到的质因子(不像什么次小质因子
m
i
n
2
5
min_25
min25筛过程中筛不到需要预处理恶心人,比如51nod 1847 奇怪的数学题),所以可以直接筛,后面就是一个
ϕ
\phi
ϕ的前缀和,具体来说他等于
2
∑
i
=
1
n
d
ϕ
(
i
)
−
⌊
n
d
⌋
2\sum_{i=1}^{\frac nd} \phi(i) - \lfloor\frac nd\rfloor
2∑i=1dnϕ(i)−⌊dn⌋
用递推版的
M
i
n
2
5
Min_25
Min25成功水到
r
k
1
rk1
rk1。
A
C
C
o
d
e
\mathcal AC \ Code
AC Code
#include<bits/stdc++.h>
#define maxn 100005
#define rep(i,j,k) for(int i=(j),LIM=(k);i<=LIM;i++)
#define per(i,j,k) for(int i=(j),LIM=(k);i>=LIM;i--)
using namespace std;
int n,K,sn,cnt,s[maxn],s1[maxn],a[maxn],g[maxn],phi[maxn];
int ID(int a){ return a <= sn ? a : cnt - n/a + 1; }
int Pow(int b,int k){ int r=1;for(;k;k>>=1,b=b*b)if(k&1)r=r*b;return r; }
double inv[maxn];
int main(){
scanf("%d%d",&n,&K);
sn = sqrt(n);
for(int i=1;i<=n;i++) a[++cnt] = (i = (n / (n / i))) ,
s[cnt] = i - 1 , s1[cnt] = 1ll * i * (i+1) / 2 - 1;
for(int i=2;i<=sn;i++){
inv[i] = 1.0 / i;
if(s[i] ^ s[i-1]) for(int j=cnt,LIM=i*i;a[j]>=LIM;j--){
int t = ID((int)(a[j] * inv[i] + 1e-9));
s[j] -= s[t] - s[i-1],
s1[j] -= (s1[t] - s1[i-1]) * i;
}
}
for(int i=1;i<=cnt;i++) phi[i] = s1[i] - s[i];
for(int i=sn;i>=1;i--) if(s[i] ^ s[i-1]){
int pw = Pow(i,K);
for(int j=cnt,LIM=i*i;a[j]>=LIM;j--){
double iv = inv[i];
for(int k=i,f=i-1;1ll*k*i <= a[j];k*=i,f*=i,iv/=i){
int t = ID((int)(a[j] * iv + 1e-9));
g[j] += pw * (s[t] - s[i-1]) + g[t];
phi[j] += f * (phi[t] - s1[i] + s[i] + i);
}
}
}
for(int i=1;i<=cnt;i++) phi[i] ++ , g[i] += s[i];
int ans = 0;
for(int i=1,nxt;i<=n;i=nxt+1){
nxt = n/(n/i);
ans += (g[ID(nxt)] - g[ID(i-1)]) * (2 * (phi[ID(n/i)] - 1) + 1);
}
unsigned int ret = ans;
printf("%u\n",ret);
}