【题目大意】

求n*n的棋盘,每行每列都有2个黑格子的方案数。

n<=10^7

【题解】

zzq的做法好神奇啊

行列建点,二分图

左边有i个点,右边有j个点的方案数 f[i,j]

左边有i个点,2个已经有1个度,右边有j个点的方案数 g[i,j]

g[i,j] = f[i-2,j-1]*j + g[j,i-2]*P(j,2)

f[i,j] = g[i,j-1] * C(i,2) = g[j,i-1] * C(j,2)

g[j,i-2] = g[i-1,j-1] * C(i-1,2) / C(j,2)

g[i,j] = g[i-2,j-2] * C(i-2,2) * j + g[i-1, j-1] * C(i-1,2) / C(j,2) * P(j,2)

g[i,j] = g[i-2,j-2] * C(i-2,2) * j + g[i-1, j-1] * C(i-1,2) * 2

g[x] = g[x, x-1]

g[x] = g[x-2] * C(x-2, 2) * (x-1) + g[x-1] * C(x-1, 2) * 2

ans = sigma (C(x,2) * g[x])

Q: 为什么从f转移到g,只乘了右边选择的部分,不管左边;从g转移到f,只乘了左边的部分,不管右边?

A: g实际的意义是我钦定左边最后两个度数为1的方案数,f实际的意义是我钦定右边最后1或2个是我最后填进来。 我从g到f,目的是消去两个度为1的点,重点是消去,我要优先考虑消除哪两个点,按照我g的定义,每两个度数为1的点作为选择,都有这么多方案,所以要乘组合数;从f到g,目的是制造两个度为1的点,按照f的定义,每1或2个点作为选择,都有这么多方案,所以要乘j和后面的那个组合数。意义在于,我要有一个顺序来填数,不能xjb填,这样会统计重复方案,我们用钦(ying)点来避免这样的问题。

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; # define RG register
# define ST static const int M = 1e7 + ;
const int mod = ; int n, g[M], ans; inline int C(int n, int k = ) {
return (ll)n * (n-) / % mod;
} int main() {
// freopen("B.in", "r", stdin);
// freopen("B.out", "w", stdout);
cin >> n;
g[] = , g[] = ;
for (int i=; i<=n; ++i) {
g[i] = 1ll * C(i-) * (i-) % mod * g[i-] % mod + 2ll * C(i-) * g[i-] % mod;
if(g[i] >= mod) g[i] -= mod;
}
for (int i=; i<=n; ++i) {
ans += 1ll * C(i) * g[i] % mod;
if(ans >= mod) ans -= mod;
}
cout << ans;
return ;
}

多贴几份考试写的各种暴力吧qwq

O(n^2)求单点暴力

# include <stdio.h>
# include <string.h>
# include <iostream>
# include <algorithm> using namespace std; typedef long long ll;
typedef unsigned long long ull;
typedef long double ld; # define RG register
# define ST static const int M = 1e4 + , N = 1e5 + ;
const int mod = ; int n, f[][M];
// row i, line2: j line1: k line0: l inline int C(int n, int k) {
if(k == ) return n;
if(k == ) return (ll)n * (n-) / % mod;
} int main() {
// freopen("B.in", "r", stdin);
// freopen("B.out", "w", stdout);
int pre = , cur = ; cin >> n;
for (int j=; j<=n; ++j) f[pre][j] = ;
f[pre][] = ;
for (int i=; i<=n; ++i) {
for (int j=; j<=i; ++j) {
f[cur][j] = ;
// i*2 = j*2 + k => k = i*2 - j*2
int k = i* - j*, l = n-j-k;
// printf("%d line2: %d line1: %d line0: %d\n", i, j, k, l);
if(l < ) continue;
if(j >= ) {
f[cur][j] += 1ll * C(k+, ) * f[pre][j-] % mod;
if(f[cur][j] >= mod) f[cur][j] -= mod;
}
if(k >= ) {
f[cur][j] += 1ll * C(l+, ) * f[pre][j] % mod;
if(f[cur][j] >= mod) f[cur][j] -= mod;
}
if(j && k) {
f[cur][j] += 1ll * C(k, ) * C(l+, ) * f[pre][j-] % mod; // 10w: need mod again
if(f[cur][j] >= mod) f[cur][j] -= mod;
}
// printf("F = %d\n", f[i][j]);
}
swap(pre, cur);
}
cout << f[pre][n] << ','; return ;
}

把含有n-...的项换成不含n的等价表示就有70分了。。

我是考试的时候打了个1w的表发现100K,压了一半,套这个做法。。50(被评测机卡)

最新文章

  1. .net core和angular2之前端篇—1
  2. Socket 类通信例子-第24章
  3. wordpress multisite functions
  4. 讨论SEO中是锚文本有效,还是纯文本有效呢?
  5. padding/margin/border 理解
  6. 378. Kth Smallest Element in a Sorted Matrix
  7. LCD控制器与驱动器
  8. SQL group by分组查询(转)
  9. USB移动硬盘WinPE启动盘的制作方法
  10. 转 Web APi之认证(Authentication)两种实现方式【二】(十三)
  11. java中线程中的相关知识点
  12. Linq to SQL 简单的增删改操作
  13. selenium 使用xpath定位不到
  14. 【Python 05】Python开发环境搭建
  15. python在读取文件时出现 &#39;gbk&#39; codec can&#39;t decode byte 0x89 in position 68: illegal multibyte sequence
  16. XML文档的简易增删查改
  17. NLP第3章 中文分词技术
  18. golang:mime.Decode、mime.DecodeHeader
  19. One-hot数据处理
  20. 进程和线程(4)-进程 vs. 线程

热门文章

  1. mysql 5.7.19 zip版本 windows安装步骤
  2. php长整型完整输出
  3. 「Haskell 学习」二 类型和函数(上)
  4. (三)宇宙大战 Space Battle -- 场景SCENE切换、UserDefaults统计分数、Particle粒子效果
  5. Java实现网页截屏功能(基于phantomJs)
  6. 爬虫:Scrapy17 - Common Practices
  7. 安装CentOS 5.x与多重引导小技巧
  8. 数据结构7——DP优化
  9. EasyUI 显示表单数据 小记
  10. Android Studio 添加模块依赖