[SCOI 2010] 字符串
[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1856
[算法]
不妨建立平面直角坐标系
将“当前已经放了的字符”看作横坐标 , 1的个数与0的个数差看作纵坐标
那么问题就转化为从(0 , 0)出发 , 每次向右上或右下移动一步 , 有多少条到达(n + m , n - m)且不经过直线y = -1的路径数
考虑用总方案数 - 经过直线y = -1的路径数
不难发现 , 总方案数为C(n + m , n)
如何计算经过直线y = -1的路径数? 可以画图分析 , 由对称性可知 , 经过直线y = -1方案数等价于从(0 , -2) 走到(n + m , n - m)的方案数 , 为C(n + m , n - 1)
答案即为C(n + m , n) - C(n + m , n - 1)
预处理阶乘逆元即可
时间复杂度 : O((N + M)logN)
[代码]
#include<bits/stdc++.h> using namespace std; #define N 2000010 typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int P = 20100403; int n , m; int fac[N] , inv[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline int exp_mod(int a , int n) { int res = 1 , b = a; while (n > 0) { if (n & 1) res = 1ll * res * b % P; b = 1ll * b * b % P; n >>= 1; } return res; } inline int C(int x , int y) { if (x < y) return 0; return 1ll * fac[x] * inv[y] % P * inv[x - y] % P; } int main() { read(n); read(m); fac[0] = 1; for (int i = 1; i <= n + m; ++i) fac[i] = 1ll * fac[i - 1] * i % P; inv[n + m] = exp_mod(fac[n + m] , P - 2); for (int i = n + m - 1; i >= 0; --i) inv[i] = 1ll * inv[i + 1] * (i + 1) % P; printf("%d\n" , ((C(n + m , n) - C(n + m , n + 1)) % P + P) % P); return 0; }