首页 > 牛客网多校训练第一场 B - Symmetric Matrix(dp)

牛客网多校训练第一场 B - Symmetric Matrix(dp)

链接:

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 }

 

转载于:https://www.cnblogs.com/hkxy125/p/9356303.html

更多相关:

  • LeetCode 191 Number of 1 Bits  解法一(较为传统都解法):使用将n不断右移,并与1想&得到1的个数;(也有使用除法/2的,明显除法的运行效率要低于位移) 时间复杂度:0(logn) 1 int hammingWeight(uint32_t n){ 2 int count=0; 3...

  • 菜鸟一枚,正在学习C++ Gui Qt4,整理很零碎,欢迎批评指正   1.窗口标题: QWidget *window = new QWidget; window->setWindowTitle("Enter Your Age"); **************************************** 关于标题...

  • 将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 总体思路是: 比较两个链表头节点,较小的插入新链表指针之后,同时较小链表指针向后移动一位 实现如下: ListNode* mergeTwo...

  • 1.直接调用微软socket对象处理 static void Main(string[] args){try{IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 });//在3721端口新建一个TcpListener对象TcpListener listener = new...

  •   现在很多地方都会用到zookeeper, 用到它的地方就是为了实现分布式。用到的场景就是服务注册,比如一个集群服务器,需要知道哪些服务器在线,哪些服务器不在线。   ZK有一个功能,就是创建临时节点,当机器启动应用的时候就会连接到一个ZK节点,然后创建一个临时节点,那么通过获取监听该路径,并且获取该路径下的节点数量就知道有哪些服务...

  • 前台到后台java时data日期类型的转化 在实体类中用@DataTimeFormat,这样设置即使传过来是空的字符串也是可以转的,要和前面传过来的格式一致,如 @XmlElement(name="BeginDate") @DateTimeFormat(pattern="yyyy-MM-dd") private Date begin...

  • Gym - 102082Ghttps://vjudge.net/problem/2198225/origin对于数列中任意一个数,要么从最左边到它不递减,要么从最右边到到它不递减,为了满足这个条件,就要移动,而移动的最少步数就是逆序对数。所以这个数要么往左移动,要么往右移动,所以两个取最小就好了 #include

  • 雪花算法根据时间戳生成有序的 64 bit 的 Long 类型的唯一 ID 各 bit 含义: 1 bit: 符号位,0 是正数 1 是负数, ID 为正数,所以恒取 041 bit: 时间差,我们可以选择一个参考点,用它来计算与当前时间的时间差 (毫秒数),41 bit 存储时间差,足够使用 69 年10 bit: 机器码,能编...

  •   这是一篇很水的blog 扫雷 link 一道很水的dp,考虑上一上,这一行,与下一行是否有雷即可 #include #include #include #include using namespace std; inline long long read...

  • 题目链接:http://codeforces.com/problemset/problem/900/D 题意:   给定x,y,问你有多少个数列a满足gcd(a[i]) = x 且 ∑(a[i]) = y。   题解:   由于gcd(a[i]) = x,所以y一定是x的倍数,否则无解。   那么原题就等价于:问你有多少个数列a满足g...

  • P2429 制杖题 题目描述 求不大于 m 的、 质因数集与给定质数集有交集的自然数之和。 输入输出格式 输入格式:第一行二个整数 n,m。 第二行 n 个整数,表示质数集内的元素 p[i]。 输出格式:一个整数,表示答案,对 376544743 取模。 输入输出样例 输入样例#1:2 15 3 5 输出样例#1:60 说...