【51nod】1776 路径计数
【51nod】1776 路径计数
我们先把前两种数给排好,排好之后会有\(a + b + 1\)个空隙可以填数,我们计算有\(k\)个空隙两端都是相同字母的方案数
可以用枚举把第二种数分成几段插进去来算,设这个方案数为\(f[k]\)
然后对于一种有\(k\)个空隙的方案数,枚举剩下的\(a + b + 1 - k\)个空隙填了\(h\)个
然后计算把\(C\)和\(D\)分成\(k + h\)段的方案数就好了,记为\(g[k + h]\)
那么如何计算\(g[i]\)呢
一段要么是偶数,\(C\)和\(D\)个数相等,一段要么是奇数,\(C\)多或者\(D\)多
对于一个\(i\),强制认为\(C\)多的有\(j\)个,那么可以求出\(D\)多的是\(k\)个,剩下的必须两两配对,把剩下的\(i - j - k\),填成\(DC\)或者\(CD\),有两种方案
然后剩下的\(CD\)的对子,扔到\(i\)个区间中排列方法是唯一的,只要计算切成\(i\)段每段可以为空的方案数是多少就行了,是个组合数
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define space putchar(' ')
#define enter putchar('\n')
#define eps 1e-10
#define ba 47
#define MAXN 1000005
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
typedef double db;
template<class T>
void read(T &res) {
res = 0;T f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 +c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {x = -x;putchar('-');}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 998244353;
int fac[10005],invfac[10005],f[5005],g[5005],pw[5005];
int a[5],N;
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void update(int &x,int y) {
x = inc(x,y);
}
int fpow(int x,int c) {
int res = 1,t = x;
while(c) {
if(c & 1) res = mul(res,t);
t = mul(t,t);
c >>= 1;
}
return res;
}
int C(int n,int m) {
if(n < m) return 0;
return mul(fac[n],mul(invfac[m],invfac[n - m]));
}
int main(){
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
fac[0] = 1;
for(int i = 1 ; i <= 10000 ; ++i) fac[i] = mul(fac[i - 1],i);
invfac[10000] = fpow(fac[10000],MOD - 2);
for(int i = 9999 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1);
pw[0] = 1;
for(int i = 1 ; i <= 5000 ; ++i) pw[i] = mul(pw[i - 1],2);
while(scanf("%d%d%d%d",&a[0],&a[1],&a[2],&a[3]) != EOF) {
N = a[0] + a[1] + a[2] + a[3];
if(!N) {puts("1");continue;}
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
for(int i = 1 ; i <= a[2] + a[3] ; ++i) {
for(int j = 0 ; j <= min(i,a[2]) ; ++j) {
if(a[3] < a[2] - j) continue;
int k = a[3] - (a[2] - j);
if(j + k > i) continue;
if(a[2] - j < i - j - k) continue;
int t = 1;
t = mul(t,C(i,j));t = mul(t,C(i - j,k));
t = mul(t,pw[i - j - k]);
int rem = a[2] - j - (i - j - k);
t = mul(t,C(rem + i - 1,i - 1));
update(g[i],t);
}
}
for(int i = 1 ; i <= a[1] ; ++i) {
int t = C(a[1] - 1,i - 1);
for(int k = max(0,i - 2) ; k <= min(a[0] - 1,i) ; ++k) {
int t0 = t;
t0 = mul(C(a[0] - 1,k),t0);t0 = mul(t0,C(2,i - k));
int p = a[0] - 1 - k + a[1] - i;
update(f[p],t0);
}
}
int ans = 0;
for(int i = 0 ; i <= a[0] + a[1] ; ++i) {
if(!f[i]) continue;
for(int h = a[0] + a[1] + 1 - i ; h >= 0 ; --h) {
int c = mul(f[i],g[i + h]);
c = mul(c,C(a[0] + a[1] + 1 - i,h));
update(ans,c);
}
}
out(ans);enter;
}
}
【51nod】1776 路径计数的更多相关文章
- 51 nod 1610 路径计数(Moblus+dp)
1610 路径计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 路径上所有边权的最大公约数定义为一条路径的值. 给定一个有向无环图.T次修改操作,每次修改一 ...
- 51nod 1682 中位数计数
1682 中位数计数基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均 ...
- 蓝桥杯 历届试题 网络寻路(dfs搜索合法路径计数)
X 国的一个网络使用若干条线路连接若干个节点.节点间的通信是双向的.某重要数据包,为了安全起见,必须恰好被转发两次到达目的地.该包可能在任意一个节点产生,我们需要知道该网络中一共有多少种不同的转发路径 ...
- 51nod 1682 中位数计数(前缀和)
51nod 1682 中位数计数 思路: sum[i]表示到i为止的前缀和(比a[i]小的记为-1,相等的记为0,比a[i]大的记为1,然后求这些-1,0,1的前缀和): hash[sum[i]+N] ...
- 堆优化Dijkstra计算最短路+路径计数
今天考试的时候遇到了一道题需要路径计数,然而蒟蒻从来没有做过,所以在考场上真的一脸懵逼.然后出题人NaVi_Awson说明天考试还会卡SPFA,吓得我赶紧又来学一波堆优化的Dijkstra(之前只会S ...
- 【洛谷】P1176: 路径计数2【递推】
P1176 路径计数2 题目描述 一个N×N的网格,你一开始在(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N),即右下角有多少种方法. 但是这个问题太简单了,所以 ...
- 牛客网 暑期ACM多校训练营(第一场)A.Monotonic Matrix-矩阵转化为格子路径的非降路径计数,Lindström-Gessel-Viennot引理-组合数学
牛客网暑期ACM多校训练营(第一场) A.Monotonic Matrix 这个题就是给你一个n*m的矩阵,往里面填{0,1,2}这三种数,要求是Ai,j⩽Ai+1,j,Ai,j⩽Ai,j+1 ,问你 ...
- 洛谷——P1176 路径计数2
P1176 路径计数2 题目描述 一个N \times NN×N的网格,你一开始在(1,1)(1,1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N,N)(N,N),即右下角有 ...
- 洛谷 P1176 路径计数2
P1176 路径计数2 题目描述 一个N×N的网格,你一开始在(1, 1),即左上角.每次只能移动到下方相邻的格子或者右方相邻的格子,问到达(N, N),即右下角有多少种方法. 但是这个问题太简单了, ...
随机推荐
- 微信小程序分页显示
<view class="tabNav"> <view wx:for="{{navTab}}" wx:key="index" ...
- IDEA构建支持cdh版本和scala的maven项目注意事项
工具和环境 idea2018.1 , scala2.11.8, scala的idea支持包,下载地址 maven3.3.9 win10系统 1.maven环境配置 下载解压maven包,(也可以使用i ...
- 20191214数组之四:数字不相同的完全平方数(关于数位上数字判断与sprintf)
sprintf用法参见之前的随笔;(以解决):
- @Transactional 注解参数详解
Transactional参数说明 参数名称 功能描述 readOnly 该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false.例如:@Transa ...
- fidder监控请求响应时间和请求IP
1.增加监控请求的详情时间 在CustomRules.js的class Handlers中增加 //添加请求的响应时间 public static BindUIColumn("Time T ...
- Laravel 中 Session 的使用问题(dd()导致laravel中session取值问题)
Laravel 中 Session 的使用问题(dd()导致laravel中session取值问题) 一.总结 一句话总结: Laravel 会首先收集需要写入 Session 的所有数据,并在用户的 ...
- TynSerial自定义对象的序列(还原)
TynSerial自定义对象的序列(还原) TynSerial是咏南中间件封装的支持数据二进制序列(还原)的类. 对于ORM来说,序列类必须序列(还原)自定义对象. 1)定义一个自定义对象 type ...
- CMMI基础知识扫盲
CMMI全称是Capability Maturity Model Integration,CMMI是个好东西来的,但行内人士对她的认识并不全面,甚至有种种的误解.尽管网上有很多CMMI相关介绍,但一般 ...
- What is the difference between XSS and CSRF from their execution perspective?
What is the difference between XSS and CSRF from their execution perspective? https://www.quora.com/ ...
- 你了解 Virtual DOM 吗?解释一下它的工作原理
Virtual DOM 是一个轻量级的 JavaScript 对象,它最初只是 real DOM 的副本.它是一个节点树,它将元素.它们的属性和内容作为对象及其属性. React 的渲染函数从 Rea ...