BBQ Hard
题目大意
给出 (n) 对 ((A_i,B_i)),求出:
[sum_{i=1}^{n}sum_{j=i+1}^{n}inom{A_i+B_i+A_j+B_j}{A_i+A_j}
]
(nle 2 imes 10^5,A_i,B_ile 2 imes 10^3)
思路
首先我们发现 (inom{A_i+B_i+A_j+B_j}{A_i+A_j}) 其实就是 ((0,0)) 走到 ((A_i+A_j,B_i+B_j)) 的方案数。然后你发现实际上也等价于 ((-A_i,-B_i)) 走到 ((A_j,B_j)) 的方案数。然后我们可以考虑 (f(i,j)) 表示以 ((i,j)) 作为终点时的方案数,然后可以得到 (f(i,j) o f(i,j)+f(i-1,j)+f(i,j-1))。然后减去一个点对自身的贡献 (/2) 就是答案。
( exttt{Code})
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 1000000007
#define MAXN 200005
#define MAXM 4005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,S,A[MAXN],B[MAXN],fac[MAXM * 2],ifac[MAXM * 2],f[MAXM][MAXM];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
int qkpow (int a,int b){int res = 1;for (;b;b >>= 1,a = mul (a,a)) if (b & 1) res = mul (res,a);return res;}
int inv (int x){return qkpow (x,mod - 2);}
int binom (int a,int b){return a >= b ? mul (fac[a],mul (ifac[b],ifac[a - b])) : 0;}
signed main(){
read (n),S = 2001;
for (Int i = 1;i <= n;++ i) read (A[i],B[i]),f[S - A[i]][S - B[i]] ++;
for (Int i = 1;i <= S * 2;++ i)
for (Int j = 1;j <= S * 2;++ j)
f[i][j] = add (f[i][j],add (f[i - 1][j],f[i][j - 1]));
fac[0] = 1;for (Int i = 1;i <= S * 4;++ i) fac[i] = mul (fac[i - 1],i);
ifac[S * 4] = inv (fac[S * 4]);for (Int i = S * 4;i;-- i) ifac[i - 1] = mul (ifac[i],i);
int ans = 0;for (Int i = 1;i <= n;++ i){
ans = add (ans,f[S + A[i]][S + B[i]]);
ans = dec (ans,binom (2 * (A[i] + B[i]),2 * A[i]));
}
ans = mul (ans,ifac[2]);
write (ans),putchar ('
');
return 0;
}
~K Perm Counting
题目大意
如果一个排列 (P) 满足对于所有的 (i) 都有 (|P_i-i| ot= k),则称排列 (P) 为合法的。现给出 (n) 和 (k),求有多少种合法的排列。
由于答案很大,请输出答案对 (924844033) 取模的结果。
(nle 2 imes 10^3,kle n-1)
思路
想到一半想不下去了。。。
首先我们想到肯定可以容斥+dp,于是我们可以设 (f(i)) 表示至少有 (i) 个位置不合法时的方案数,可以得到答案即为:
[sum_{i=0}^{n}(-1)^if(i)(n-i)!
]
于是问题就是如何求出 (f(i))。
然后我们可以转换成下面一个问题:
然后你发现就是对每条链求最大独立集,于是我们可以设 (g(i,j)) 表示前面 (i) 个点(假设链上的点都是排在一起的)有 (j) 个不合法点的方案数,可以得到转移式:
[g(i,j)=g(i-1,j)+g(i-2,j-1)
]
每个链的链头单独考虑即可。
( exttt{Code})
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 924844033
#define MAXN 2005
template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
int n,m,a[MAXN],fac[MAXN],f[MAXN][MAXN];
int mul (int a,int b){return 1ll * a * b % mod;}
int dec (int a,int b){return a >= b ? a - b : a + mod - b;}
int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;}
signed main(){
read (n,m);
fac[0] = 1;for (Int i = 1;i <= n;++ i) fac[i] = mul (fac[i - 1],i);
int siz = 0;for (Int i = 1;i <= (n - m) % m;++ i) a[siz += (n - m) / m + 1] = 1,a[siz += (n - m) / m + 1] = 1;
for (Int i = 1;i <= m - (n - m) % m;++ i) a[siz += (n - m) / m] = 1,a[siz += (n - m) / m] = 1;
f[0][0] = a[0] = 1;
for (Int i = 1;i <= siz;++ i)
for (Int j = 0;j <= i;++ j)
f[i][j] = add (f[i - 1][j],j ? f[i - 1 - (!a[i - 1])][j - 1] : 0);
int ans = 0;
for (Int i = 0,tmp;i <= n;++ i) tmp = mul (fac[n - i],f[siz][i]),ans = i & 1 ? dec (ans,tmp) : add (ans,tmp);
write (ans),putchar ('
');
return 0;
}