• 牛客网多校训练第一场 B


    链接:

    https://www.nowcoder.com/acm/contest/139/B

    题意:

    求满足以下条件的n*n矩阵A的数量模m:
    A(i,j) ∈ {0,1,2}, 1≤i,j≤n.
    A(i,j) = A(j,i), 1≤i,j≤n.
    A(i,1) + A(i,2) + ... + A(i,n) = 2, 1≤i≤n.
    A(1,1) = A(2,2) = ... = A(n,n) = 0.
    其中1≤n≤1e5, 1≤m≤1e9。

    分析:

    把矩阵看成无向图的邻接矩阵,即要求所有点度为2,即每个点都属于一个环。
    设d(n)表示n个点满足条件的图的数量。
    思考每加入一个新点,如何从已知状态转移。
    1.从前面的n-1个点中选出1个点与新点构成环,有(n-1)d(n-2)种方案。
    2.从前面的n-1个点中选出k个点,剩下的点与新点连成环,
    有sum(C(n-1,k)*(n-1-k)!/2)(2≤k≤n-3)种方案,
    因为剩下的点与新点连成环时的对称性,所以要除以2。
    将以上两式化简相加,得d(n) = (n-1)d(n-2) + sum((n-1)!d(k)/k!/2)(2≤k≤n-3)。
    设f(n) = sum((n-1)!d(k)/k!/2)(2≤k≤n-3)。
    可以发现,f(n)也是可以递推的,即f(n) = (n-1)f(n-1) + (n-1)(n-2)d(n-3)/2。
    所以,线性时间递推f和d数组即可。

    代码:

     1 import java.io.*;
     2 import java.util.*;
     3  
     4 public class Main {
     5     Scanner cin = new Scanner(new BufferedInputStream(System.in));
     6     final int UP = (int)1e5 + 5;
     7     long d[] = new long[UP], f[] = new long[UP];
     8      
     9     void MAIN() {
    10         while(cin.hasNext()) {
    11             int n = cin.nextInt();
    12             long m = cin.nextInt();
    13              
    14             d[2] = d[3] = f[3] = 1 % m;
    15             for(int i = 4; i <= n; i++) {
    16                 f[i] = ((i-1) * f[i-1] % m + (long)(i-1) * (i-2) / 2 % m * d[i-3] % m) % m;
    17                 d[i] = ((i-1) * d[i-2] % m + f[i]) % m;
    18             }
    19             System.out.println(d[n]);
    20         }
    21     }
    22      
    23     public static void main(String args[]) { new Main().MAIN(); }
    24 }
  • 相关阅读:
    day23,xml 和面向对象
    day22,ConfigParser,subprocess,xlrd三个模块
    re的总结
    day20,日志和正则表达式
    day19,序列化与反序列化总结,和其它的有些模块
    字符串的内建函数
    字符串和编码
    python解释器分类
    git &github 快速入门
    do export method of oracle all database tables with dmp files.
  • 原文地址:https://www.cnblogs.com/hkxy125/p/9356303.html
Copyright © 2020-2023  润新知