牛客小白月赛14 A. 简单计数

链接

https://ac.nowcoder.com/acm/contest/879/A

题意

完全图中从 点 1 1 1 出发,经过 k k k 条边(可重复)回到点 1 1 1 的方案数。

思路一

设矩阵 A A A 中每个元素都为 1 1 1,矩阵 I I I 为单位矩阵,

所以根据题意,我们要求的就是 ( A − I ) 0 , 0 k (A-I)^k_{0,0} (AI)0,0k

根据矩阵二项式定理: ( A − I ) k = ∑ i = 0 k ( k i ) A i ( − 1 ) k − i (A-I)^k=\sum_{i=0}^{k}\binom{k}{i}A^i(-1)^{k-i} (AI)k=i=0k(ik)Ai(1)ki

所以

( A − I ) 0 , 0 k = ∑ i = 0 k ( k i ) n max ⁡ ( 0 , i − 1 ) ( − 1 ) k − i = ∑ i = 0 k ( k i ) n max ⁡ ( 1 , i ) n ( − 1 ) k − i = 1 n ( ( n − 1 ) k − ( k 0 ) n 0 ( − 1 ) k + ( k 0 ) n 1 ( − 1 ) k ) = ( n − 1 ) k + ( − 1 ) k ( n − 1 ) n \begin{aligned} (A-I)^k_{0,0} &=\sum_{i=0}^{k}\binom{k}{i}n^{\max(0,i-1)}(-1)^{k-i}\\ &=\sum_{i=0}^{k}\binom{k}{i}\frac{n^{\max(1,i)}}{n}(-1)^{k-i}\\ &=\frac{1}{n}((n-1)^k-\binom{k}{0}n^{0}(-1)^{k}+\binom{k}{0}n^{1}(-1)^{k})\\ &=\frac{(n-1)^k+(-1)^k(n-1)}{n}\\ \end{aligned} (AI)0,0k=i=0k(ik)nmax(0,i1)(1)ki=i=0k(ik)nnmax(1,i)(1)ki=n1((n1)k(0k)n0(1)k+(0k)n1(1)k)=n(n1)k+(1)k(n1)

代码一

#include 
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const int MOD=998244353;
LL n,k;
LL qpow(LL a,LL b) {
    LL ret=1;
    while(b) {
        if(b&1) ret=ret*a%MOD;
        a=a*a%MOD;
        b>>=1;
    }
    return ret;
}
int main() {
    //freopen("E:/OneDrive/IO/in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin>>n>>k;
    cout<<(qpow(n-1,k)+(n-1)*(k&1?-1:1)+MOD)%MOD*qpow(n,MOD-2)%MOD<<'\n';
    return 0;
}

思路二

d p i , 1 dp_{i,1} dpi,1 为经过 i i i 条边在点 1 1 1 的方案数, d p i , 0 dp_{i,0} dpi,0 为经过 i i i 条边不在点 1 1 1 的方案数。

转移方程:

{ d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] d p [ i ] [ 0 ] = ( n − 1 ) d p [ i − 1 ] [ 1 ] + ( n − 2 ) d p [ i − 1 ] [ 0 ] \begin{cases} dp[i][1]=dp[i-1][0]\\ dp[i][0]=(n-1)dp[i-1][1]+(n-2)dp[i-1][0] \end{cases} {dp[i][1]=dp[i1][0]dp[i][0]=(n1)dp[i1][1]+(n2)dp[i1][0]

构造矩阵加速递推。

代码二

#include 
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const LL MOD=998244353;
int sz;
struct M {
    LL a[105][105];
    void clear() {memset(a,0,sizeof a);}
    M() {clear();}
    void init() {
        clear();
        for(int i=0;i<sz;i++) a[i][i]=1;
    }
    M operator + (const M &T) const {
        M ret;
        for(int i=0;i<sz;i++)
            for(int j=0;j<sz;j++)
                ret.a[i][j]=(a[i][j]+T.a[i][j])%MOD;
        return ret;
    }
    M operator - (const M &T) const {
        M ret;
        for(int i=0;i<sz;i++)
            for(int j=0;j<sz;j++)
                ret.a[i][j]=(a[i][j]-T.a[i][j]+MOD)%MOD;
        return ret;
    }
    M operator * (const LL &v) const {
        M ret;
        for(int i=0;i<sz;i++)
            for(int j=0;j<sz;j++) {
                if(!a[i][j]) continue;
                ret.a[i][j]=a[i][j]*v%MOD;
            }
        return ret;
    }
    M operator * (const M &T) const {
        M ret;
        for(int i=0;i<sz;i++)
            for(int k=0;k<sz;k++) {
                LL t=a[i][k];
                if(!t) continue;
                for(int j=0;j<sz;j++) {
                    if(!T.a[k][j]) continue;
                    ret.a[i][j]=(ret.a[i][j]+T.a[k][j]*t%MOD)%MOD;
                }
            }
        return ret;
    }
    M operator ^ (LL b) const {
        M ret,bas;
        for(int i=0;i<sz;i++) ret.a[i][i]=1;
        for(int i=0;i<sz;i++)
            for(int j=0;j<sz;j++)
                bas.a[i][j]=a[i][j];
        while(b) {
            if(b&1) ret=ret*bas;
            bas=bas*bas;
            b>>=1;
        }
        return ret;
    }
    void print() {
        for(int i=0;i<sz;i++)
            for(int j=0;j<sz;j++)
                cout<<a[i][j]<<" \n"[j==sz-1];
    }
};
int main() {
    //freopen("E:/OneDrive/IO/in.txt","r",stdin);
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    LL n,k;
    cin>>n>>k;
    sz=2;
    M t1,t2;
    t1.a[0][0]=1;
    t2.a[1][0]=1,t2.a[0][1]=n-1,t2.a[1][1]=n-2;
    t1*=t2^k;
    cout<<t1.a[0][0]<<'\n';
    return 0;
}

你可能感兴趣的:(数学,——,线性代数,概率论)