关于单位根反演
先上单位根反演的公式:
我们来考虑证明这个公式,分类讨论:
若 \(k|n\),那么:
若 \(k \nmid n\),那么根据等比数列求和有:
由于其分子为 \(1−1=0\),因此该公式成立。
可以导出下式
#6485. LJJ 学二项式定理
输入以下变量的值:\(a_0,a_1,a_2,a_3,s,n\),求以下式子的值:
有:
二项式定理有:
注意到 \(3\) 是 \(998244353\) 的原根,令 \(w_4^1=3^{\frac{998244352}{4}}\),快速幂即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const long long md=998244353;
inline long long pwr(long long x,long long y){
int res=1;
while(y){
if(y&1)res=res*x%md;
x=x*x%md;y>>=1;
}
return res;
}
long long n,s,a[4],G=pwr(3,(md-1)/4),inv4=pwr(4,md-2);
inline void solve(){
scanf("%lld%lld%lld%lld%lld%lld",&n,&s,&a[0],&a[1],&a[2],&a[3]);
long long res=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++)res=(res+a[i]*pwr(G,md-1-i*j)%md*pwr(s*pwr(G,j)%md+1,n))%md;
}
printf("%lld\n",inv4*res%md);
}
int T;
int main(){
scanf("%d",&T);
while(T--)solve();
return 0;
}
P5591 小猪佩奇学数学
给定 \(n,p,k\) ,询问
不难发现:
进一步,有:
带入原式中,有:
然而这是不对的,我们还需要特判 \(t=0\) 也就是 \(w_k^0=1\) 的情况:
因此,最终答案为:
点击查看代码
#include <bits/stdc++.h>
const int md=998244353,G=3;
inline int pwr(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%md;
x=1ll*x*x%md;y>>=1;
}
return res;
}
int n,p,k,w[2000005];
int main(){
scanf("%d%d%d",&n,&p,&k);
w[0]=1;w[1]=pwr(G,(md-1)/k);
for(int i=2;i<k;i++)w[i]=1ll*w[i-1]*w[1]%md;
int ans=(1ll*n*p%md*pwr(p+1,n-1)%md+pwr(p+1,n))%md;
for(int i=1;i<k;i++){
int now=1ll*w[i]*pwr(1ll*w[i]*p%md+1,n)%md;
now=(now-pwr(p+1,n)+md)%md;
ans=(ans+1ll*now*pwr(w[i]-1,md-2)%md)%md;
}
ans=(1ll*ans*pwr(k,md-2)%md-pwr(p+1,n)+md)%md;
printf("%d\n", ans);
return 0;
}
亿点整理
首先考虑一般的二分图,如何用线性代数方法检查是否有完美匹配:
我们可以构造 \(n\) 阶方阵 \(M\) 。若有 \(X\in (N_+)^{n\times n}\),那么:
结论是:
原二分图有完美匹配 ⇔ 存在 \(X\) 使得 \(det(M)!=0\) 。
对于一个随机边权的邻接矩阵,它的行列式在某种意义上可以看作另一个随机边权的邻接矩阵的和积式,一个临界矩阵的和积式不为 \(0\) 说明该邻接矩阵对应的图有完美匹配。
当然,由于涉及了随机数,而且是在模意义下求行列式,对于一张存在完美匹配的图,其行列式也可能在某些情况下算出来是 \(0\),最好多做几次。
那么考虑这道题,我们相当于多要求,当完美匹配的权为 \(S\) 时,还需要有 \(k|S\),即求 \(det(M)[k|S]\) 。
有:
我们把 \(S\) 放入 \(M\) 中,有:
外层枚举 \(i\) ,对每个 \(M\) 求行列式加起来即可,时间复杂度 \(O(n^4)\) ,除此之外还需要找一下形如 \(i\times k+1\) 的质数做模数,以及该模数的原根。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
int n,k,md,G;
inline bool isprime(int x){
for(int i=2;i*i<=x;i++)if(x%i==0)return 0;
return 1;
}
inline int pwr(int x,int y){
int res=1;
while(y){
if(y&1)res=1ll*res*x%md;
x=1ll*x*x%md;y>>=1;
}
return res;
}
inline bool isG(int x){
if(pwr(x,md-1)!=1)return 0;
for(int i=2;i<md-1;i++)if((md-1)%i==0&&pwr(x,i)==1)return 0;
return 1;
}
struct mat{
int a[105][105];
inline int* operator [](int t){
return a[t];
}
inline int Det(){
int res=1;
for(int i=1;i<=n;i++){
int loc=i;for(int j=n;j>=i;j--)if(a[j][i])loc=j;
if(i!=loc)swap(a[i],a[loc]),res=-res;
for(int j=i+1;j<=n;j++){
int tmp=1ll*a[j][i]*pwr(a[i][i],md-2)%md;
for(int t=i;t<=n;t++)a[j][t]=(a[j][t]-1ll*a[i][t]*tmp)%md;
}
}
for(int i=1;i<=n;i++)res=1ll*res*a[i][i]%md;
return (res+md)%md;
}
}tmp[105],bas,val;
inline void init(){
for(int i=1;i<=1e4;i++)if(isprime(i*k+1))md=i*k+1;
for(int i=2;i<md;i++){
if(isG(i)){G=i;break;}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)scanf("%d",&val[i][j]);
}
int ans=0;
for(int t=1;t<=3;t++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++)bas[i][j]=rand()%md;
}
for(int i=0;i<k;i++){
for(int j=1;j<=n;j++){
for(int t=1;t<=n;t++){
if(val[j][t]==-1)tmp[i][j][t]=0;
else tmp[i][j][t]=1ll*bas[j][t]*pwr(G,1ll*val[j][t]*i*(md-1)/k)%md;
}
}
ans=(ans+tmp[i].Det())%md;
}
}
puts(ans?"Yes":"No");
}
int main(){
freopen("sort.in","r",stdin);
freopen("sort.out","w",stdout);
scanf("%d%d",&n,&k);
srand(time(0));init();
return 0;
}