题目大意:给定
n,m
n
,
m
,问有多少
n
n
行列的矩阵
A
A
,满足:
1);
2)
∃i,j∈[1,n],∀p,q≥0,(Ap)i,j=(Aq)i,j
∃
i
,
j
∈
[
1
,
n
]
,
∀
p
,
q
≥
0
,
(
A
p
)
i
,
j
=
(
A
q
)
i
,
j
。此时称
(i,j)
(
i
,
j
)
为矩阵
A
A
的不动点。
请注意,,即
(A0)i,j⇐⇒[i=j]
(
A
0
)
i
,
j
⇐⇒
[
i
=
j
]
.
题解:
先把n=1判掉。
首先不要把它当成线性代数题,将其视为邻接矩阵。
那么就是要找到一对点,使得其两点间不同长度路径方案相同。
首先如果这个图不弱连通,那么一定存在一对点,永远到不了。
然后显然这个可以加强为不强联通。
然后过了一会,恩,也就是两个小时吧,意识到这个条件其实是充要条件(我会告诉你其间我还想到了什么exgcd之类的么)。
考虑反证,假设
(x,y)
(
x
,
y
)
是其不动点。
1)若
x≠y
x
≠
y
,则
(Ap)x,y=(A0)x,y=0
(
A
p
)
x
,
y
=
(
A
0
)
x
,
y
=
0
,但是因为其强联通,所以存在一个时刻
x
x
能到达。
2)否则
x=y,(Ap)x,y=(A0)x,x=1
x
=
y
,
(
A
p
)
x
,
y
=
(
A
0
)
x
,
x
=
1
,但这也是不可能的,因为其强联通并且
n≥2
n
≥
2
,所以存在一个时刻,
x
x
能走一个与其相连的点然后从
z
z
走到;同时也可以一直走自环,因此方案数就至少是
2
2
了。
问题转化为个点的有向强联通图计数,考虑主旋律的做法(顺便就当时主旋律的题解了吧)。显然自环不影响图的强联通性因此下文暂时不考虑。
先考虑一个有点问题的做法。
令
fn
f
n
表示答案,
gn
g
n
表示若干个强联通分量(下文简记SCC)的方案数,也就是
gn=∑ni=1(n−1i−1)fign−i
g
n
=
∑
i
=
1
n
(
n
−
1
i
−
1
)
f
i
g
n
−
i
;
考虑计算
gn
g
n
,一个想法是,考虑所有不合g法的情况,缩点之后一定存在边。
钦定一些点是出度为0的点,然后剩下的点内部和从剩下的点到钦定的点间可以随便连,钦定的点就是g,钦定的点不能连向剩下的点,算出这个从总数中减去:
gn=hn−∑n−1i=1(ni)mi(n−i)hn−igi
g
n
=
h
n
−
∑
i
=
1
n
−
1
(
n
i
)
m
i
(
n
−
i
)
h
n
−
i
g
i
其中
hn
h
n
表示
n
n
个点的有向图
但这么算是肯定有问题的,但是我们想知道到底问题在哪里:
考虑真实情况是钦定的点有个,缩点后有 p p 个,会被计算几次。
首先若。
考虑枚举的
gi
g
i
只能恰好包含
p
p
的一个非空子集,枚举这个的大小:,其会被计算
∑pt=1(pt)
∑
t
=
1
p
(
p
t
)
这么多次。
我们希望其被计算1次,其实也很简单:给它配上一个容斥系数就可以了:
∑pt=1(pt)(−1)t+1=1
∑
t
=
1
p
(
p
t
)
(
−
1
)
t
+
1
=
1
,也就是说这个系数应该配到连通块个数上,即
gn
g
n
应当定义为,一个每个弱联通分量都是SCC的图,若其有
t
t
个联通块,则对贡献是
(−1)t+1
(
−
1
)
t
+
1
。
考虑在配上系数后
k=n
k
=
n
的情况,此时由于
i<n
i
<
n
所以
t
t
不能枚举到p的全集:。
因而最终
k<n
k
<
n
会被计算
1−1=0
1
−
1
=
0
次,
k=n
k
=
n
会被计算
1−((−1)p+1)=(−1)p+1
1
−
(
(
−
1
)
p
+
1
)
=
(
−
1
)
p
+
1
次,发现正好就是
gn
g
n
的定义。
用
gn
g
n
推导出
fn
f
n
依然可以用最开始的式子,也就是与那个
−1
−
1
的系数无关(因为本质上只不过是奇偶分开讨论而已)。
这样就做完了!开森。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<utility>
#define lint long long
#define p 1000000007
#define gc getchar()
#define mp make_pair
#define fir first
#define sec second
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define clr(a,n) memset(a,0,sizeof(int)*((n)+1))
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
#define N 3010
using namespace std;
typedef pair<int,int> pii;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
#define H(x) mi[(x)*((x)-1)]
int f[N],g[N],mi[N*N],c[N][N],h[N],fac[N],facinv[N];
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%p) (k&1)?ans=(lint)ans*x%p:0;return ans; }
inline int prelude(int n,int m)
{
fac[0]=1;rep(i,1,n) fac[i]=(lint)fac[i-1]*i%p;facinv[n]=fast_pow(fac[n],p-2),mi[0]=1;
for(int i=n-1;i>=0;i--) facinv[i]=facinv[i+1]*(i+1ll)%p;rep(i,1,n*n) mi[i]=(lint)mi[i-1]*m%p;return 0;
}
int main()
{
int n=inn(),m=inn();if(n==1&&m==2) return !printf("1\n");
prelude(n,m),f[1]=g[1]=1;rep(i,1,n) h[i]=H(i);rep(i,0,n) c[i][0]=1;
rep(i,1,n) rep(j,1,i) c[i][j]=c[i-1][j-1]+c[i-1][j],(c[i][j]>=p?c[i][j]-=p:0);
rep(i,2,n)
{
g[i]=h[i];
rep(j,1,i-1) g[i]-=(lint)c[i][j]*h[i-j]%p*g[j]%p*mi[j*(i-j)]%p,(g[i]<0?g[i]+=p:0);
f[i]=g[i];rep(j,1,i-1) f[i]+=(lint)c[i-1][j-1]*f[j]%p*g[i-j]%p,(f[i]>=p?f[i]-=p:0);
}
return !printf("%lld\n",(lint)mi[n]*((h[n]-f[n]+p)%p)%p);
}