数字表格
莫比乌斯反演
首先,要把
∏i=1n∏j=1mf[gcd(i,j)]∏i=1n∏j=1mf[gcd(i,j)]∏i=1n∏j=1mf[gcd(i,j)]
∏
i
=
1
n
∏
j
=
1
m
f
[
g
c
d
(
i
,
j
)
]
∏
i
=
1
n
∏
j
=
1
m
f
[
gcd
(
i
,
j
)
]
∏
i
=
1
n
∏
j
=
1
m
f
[
g
c
d
(
i
,
j
)
]
换一个方向去思考,即不枚举
i,ji,ji,j
i
,
j
i
,
j
i
,
j
,而是枚举
d=gcd(i,j)d=gcd(i,j)d=gcd(i,j)
d
=
g
c
d
(
i
,
j
)
d
=
gcd
(
i
,
j
)
d
=
g
c
d
(
i
,
j
)
。可以得到,在这个表格里,f[d]f[d]f[d] 出现的次数就是
∑i=1n∑j=1m[gcd(i,j)=d]∑i=1n∑j=1m[gcd(i,j)=d]∑i=1n∑j=1m[gcd(i,j)=d]
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
∑
i
=
1
n
∑
j
=
1
m
[
gcd
(
i
,
j
)
=
d
]
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
。
所以:
Ans=∏df[d]∑i=1n∑j=1m[gcd(i,j)=d]Ans=∏df[d]∑ni=1∑mj=1[gcd(i,j)=d]Ans=∏df[d]∑i=1n∑j=1m[gcd(i,j)=d]=∏df[d]∑i=1⌊nd⌋∑j=1⌊md⌋[gcd(i,j)=1]=∏df[d]∑⌊nd⌋i=1∑⌊md⌋j=1[gcd(i,j)=1]=∏df[d]∑i=1⌊dn⌋∑j=1⌊dm⌋[gcd(i,j)=1]
A
n
s
=
∏
d
f
[
d
]
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
A
n
s
=
∏
d
f
[
d
]
∑
i
=
1
n
∑
j
=
1
m
[
gcd
(
i
,
j
)
=
d
]
A
n
s
=
∏
d
f
[
d
]
∑
i
=
1
n
∑
j
=
1
m
[
g
c
d
(
i
,
j
)
=
d
]
=
∏
d
f
[
d
]
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
g
c
d
(
i
,
j
)
=
1
]
=
∏
d
f
[
d
]
∑
i
=
1
⌊
n
d
⌋
∑
j
=
1
⌊
m
d
⌋
[
gcd
(
i
,
j
)
=
1
]
=
∏
d
f
[
d
]
∑
i
=
1
⌊
d
n
⌋
∑
j
=
1
⌊
d
m
⌋
[
g
c
d
(
i
,
j
)
=
1
]
而
∑i=1x∑j=1y[gcd(i,j)=1]∑i=1x∑j=1y[gcd(i,j)=1]∑i=1x∑j=1y[gcd(i,j)=1]是一个经典问题,它等于∑d⌊xd⌋⌊yd⌋μ(d)∑d⌊xd⌋⌊yd⌋μ(d)∑d⌊dx⌋⌊dy⌋μ(d)
∑
i
=
1
x
∑
j
=
1
y
[
g
c
d
(
i
,
j
)
=
1
]
∑
i
=
1
x
∑
j
=
1
y
[
gcd
(
i
,
j
)
=
1
]
∑
i
=
1
x
∑
j
=
1
y
[
g
c
d
(
i
,
j
)
=
1
]
是
一
个
经
典
问
题
,
它
等
于
∑
d
⌊
x
d
⌋
⌊
y
d
⌋
μ
(
d
)
∑
d
⌊
x
d
⌋
⌊
y
d
⌋
μ
(
d
)
∑
d
⌊
d
x
⌋
⌊
d
y
⌋
μ
(
d
)
即原式等于
∏df[d]∑k⌊ndk⌋⌊mdk⌋μ(k)∏df[d]∑k⌊ndk⌋⌊mdk⌋μ(k)∏df[d]∑k⌊dkn⌋⌊dkm⌋μ(k)
∏
d
f
[
d
]
∑
k
⌊
n
d
k
⌋
⌊
m
d
k
⌋
μ
(
k
)
∏
d
f
[
d
]
∑
k
⌊
n
d
k
⌋
⌊
m
d
k
⌋
μ
(
k
)
∏
d
f
[
d
]
∑
k
⌊
d
k
n
⌋
⌊
d
k
m
⌋
μ
(
k
)
继续考虑。可以发现,
⌊ndk⌋⌊ndk⌋⌊dkn⌋和⌊mdk⌋⌊mdk⌋⌊dkm⌋
⌊
n
d
k
⌋
⌊
n
d
k
⌋
⌊
d
k
n
⌋
和
⌊
m
d
k
⌋
⌊
m
d
k
⌋
⌊
d
k
m
⌋
这两个式子不容易直接分块。所以这里令
u=dku=dku=dk
u
=
d
k
u
=
d
k
u
=
d
k
,原式化为:
∏u∏k∣uf[uk]μ(k)⌊nu⌋⌊mu⌋∏u∏k|uf[uk]μ(k)⌊nu⌋⌊mu⌋∏u∏k∣uf[ku]μ(k)⌊un⌋⌊um⌋=∏u(∏k∣uf[uk]μ(k))⌊nu⌋⌊mu⌋=∏u(∏k|uf[uk]μ(k))⌊nu⌋⌊mu⌋=∏u(∏k∣uf[ku]μ(k))⌊un⌋⌊um⌋
∏
u
∏
k
∣
u
f
[
u
k
]
μ
(
k
)
⌊
n
u
⌋
⌊
m
u
⌋
∏
u
∏
k
|
u
f
[
u
k
]
μ
(
k
)
⌊
n
u
⌋
⌊
m
u
⌋
∏
u
∏
k
∣
u
f
[
k
u
]
μ
(
k
)
⌊
u
n
⌋
⌊
u
m
⌋
=
∏
u
(
∏
k
∣
u
f
[
u
k
]
μ
(
k
)
)
⌊
n
u
⌋
⌊
m
u
⌋
=
∏
u
(
∏
k
|
u
f
[
u
k
]
μ
(
k
)
)
⌊
n
u
⌋
⌊
m
u
⌋
=
∏
u
(
∏
k
∣
u
f
[
k
u
]
μ
(
k
)
)
⌊
u
n
⌋
⌊
u
m
⌋
这样就可以将
⌊nu⌋⌊nu⌋⌊un⌋和⌊mu⌋⌊mu⌋⌊um⌋
⌊
n
u
⌋
⌊
n
u
⌋
⌊
u
n
⌋
和
⌊
m
u
⌋
⌊
m
u
⌋
⌊
u
m
⌋
的值分块了。令
F[u]=∏k∣uf[uk]μ(k)F[u]=∏k|uf[uk]μ(k)F[u]=∏k∣uf[ku]μ(k)
F
[
u
]
=
∏
k
∣
u
f
[
u
k
]
μ
(
k
)
F
[
u
]
=
∏
k
|
u
f
[
u
k
]
μ
(
k
)
F
[
u
]
=
∏
k
∣
u
f
[
k
u
]
μ
(
k
)
,那么就可以预处理FFF 的前缀积,计算区间的积时使用逆元计算。
不知为什么,不开longlongtle
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const long long N=1000000,mod=1000000007;
long long pr[N+10],tot,miu[N+10],n,m,f[N+10],g[N+10],F[N+10],T,ans;bool ip[N+10];
inline long long read()
{
long long x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
long long fastpow(long long a,long long k){long long ans=1;
while(k){
if(k&1) ans=(1ll*ans*a)%mod;
a=(1ll*a*a)%mod;k>>=1;
}
return ans%mod;
}
void pre(){miu[1]=f[1]=g[1]=ip[1]=ip[0]=F[0]=F[1]=1;
for(long long i=2;i<=N;i++) {
f[i]=(f[i-1]+f[i-2])%mod; g[i]=fastpow(f[i],mod-2);F[i]=1;
if(!ip[i]) pr[++tot]=i,miu[i]=-1;
for(long long j=1;j<=tot&&i*pr[j]<=N;j++){
ip[pr[j]*i]=1;miu[pr[j]*i]=i%pr[j]?-miu[i]:0;
if(i%pr[j]==0) break;
}
}
for(long long i=1;i<=N;i++){
if(!miu[i]) continue;
for(long long j=i;j<=N;j+=i) F[j]=1ll*F[j]*(miu[i]==1?f[j/i]:g[j/i])%mod;
}
for(long long i=2;i<=N;i++) F[i]=1ll*F[i]*F[i-1]%mod;
}
int main(){pre();
T=read();
while(T--){ans=1;
n=read(),m=read();if(n>m) swap(n,m);
for(long long i=1,j,tmp;i<=n;){
j=min(n/(n/i),m/(m/i));
tmp=1ll*F[j]*fastpow(F[i-1],mod-2)%mod;
ans=(1ll*ans*fastpow(tmp,(n/i)*(m/i)%(mod-1)))%mod;
i=j+1;
}
printf("%lld\n",ans);
}
}
[SDOI2017]序列计数
f[i][j]+=f[i−1][q]((q+k)==p∗x,x∈R)
f
[
i
]
[
j
]
+
=
f
[
i
−
1
]
[
q
]
(
(
q
+
k
)
==
p
∗
x
,
x
∈
R
)
很显然
f[i][j]=f[i][q]∗一个p∗p的矩阵
f
[
i
]
[
j
]
=
f
[
i
]
[
q
]
∗
一
个
p
∗
p
的
矩
阵
就用矩阵快速幂了
// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
const int N=2*1e7+9,mod=20170408;
int ip[N],pr[N],tot,miu[N],n,m,p,s[101],ans;
void pre(){ip[1]=1;
for(int i=2;i<=N;i++) {
if(!ip[i]) pr[++tot]=i;
for(int j=1;j<=tot&&i*pr[j]<=N;j++){
ip[pr[j]*i]=1; if(i%pr[j]==0) break;
}
}
}
struct Mat{
int mat[101][101];Mat(){memset(mat,0,sizeof mat);}
Mat operator *(Mat b)const{
Mat ans;
for(int i=0;i<p;i++) for(int k=0;k<p;k++)for(int j=0;j<p;j++)
ans.mat[i][j]=(ans.mat[i][j]+1ll*mat[i][k]*b.mat[k][j]%mod)%mod;
return ans;
}
}tmp1,tmp2,tmp3;
int main(){pre();
scanf("%d%d%d",&n,&m,&p);
for(int i=1;i<=m;i++) s[i%p]++;tmp1.mat[0][0]=1;
for(int i=0;i<p;i++) for(int j=0;j<p;j++) tmp2.mat[i][(i+j)%p]=s[j]%mod;
for(int i=n;i;i>>=1,tmp2=tmp2*tmp2) if(i&1) tmp1=tmp1*tmp2;
ans=tmp1.mat[0][0];memset(s,0,sizeof s);
for(int i=1;i<=m;i++) if(ip[i])s[i%p]++;tmp3.mat[0][0]=1;
for(int i=0;i<p;i++) for(int j=0;j<p;j++) tmp2.mat[i][(i+j)%p]=s[j]%mod;
for(int i=n;i;i>>=1,tmp2=tmp2*tmp2) if(i&1) tmp3=tmp3*tmp2;
ans-=tmp3.mat[0][0];
printf("%d",(ans+mod)%mod);
}
新生舞会
01分数规划+带权二分图匹配
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int M=210;queue<int>q;const double INF=20000000.0;
int n,S,T,mflow;bool vis[M];double cos[M*M],mcost,a[M][M],b[M][M],dis[M];
int nex[M*M],head[M],to[M*M],cap[M*M],pre[M],id[M],tot,flow[M];
void add(int x,int y,int z,double w){
nex[++tot]=head[x];
cos[tot]=w;cap[tot]=z;
head[x]=tot;to[tot]=y;
}
int spfa(int s,int t){
memset(vis,0,sizeof vis);memset(pre,-1,sizeof pre);
for(int i=0;i<=2*n+1;i++) dis[i]=INF;
dis[s]=0;q.push(s);vis[s]=1;flow[s]=INF;
while(!q.empty()){
int x=q.front();q.pop(),vis[x]=0;
for(int i=head[x],tmp;i>=2;i=nex[i]){
if(dis[tmp=to[i]]>dis[x]+cos[i]&&cap[i]){
dis[tmp]=dis[x]+cos[i];id[tmp]=i;
pre[tmp]=x;flow[tmp]=min(flow[x],cap[i]);
if(!vis[tmp]) q.push(tmp),vis[tmp]=1;
}
}
}
return dis[t]<INF;
}
bool check(double x){
tot=1;mflow=mcost=0;memset(head,0,sizeof head);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) add(i,j+n,1,x*b[i][j]-a[i][j]),add(j+n,i,0,a[i][j]-x*b[i][j]);
for(int i=1;i<=n;i++) add(S,i,1,0),add(i,S,0,0),add(i+n,T,1,0),add(T,i+n,0,0);
while(spfa(S,T)){int k=T;
while(k!=S){
cap[id[k]]-=flow[T],cap[id[k]^1]+=flow[T];
k=pre[k];
}
mflow+=flow[T];mcost+=(double)flow[T]*dis[T];
}
return -mcost>=0.0000001;
}
int main(){
scanf("%d",&n);T=2*n+1;
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) scanf("%lf",&a[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++) scanf("%lf",&b[i][j]);
double l=0,r=1e5;
while(l+0.0000001<=r){double mid=(l+r)/2;
if(check(mid)) l=mid;else r=mid;
}
printf("%lf",l);
}