Live2D

2020-10-12 集训题目题解

BBQ Hard

题目传送门

题目大意

给出 \(n\)\((A_i,B_i)\),求出:

\[\sum_{i=1}^{n}\sum_{j=i+1}^{n}\binom{A_i+B_i+A_j+B_j}{A_i+A_j} \]

\(n\le 2\times 10^5,A_i,B_i\le 2\times 10^3\)

思路

首先我们发现 \(\binom{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)\to f(i,j)+f(i-1,j)+f(i,j-1)\)。然后减去一个点对自身的贡献 \(/2\) 就是答案。

\(\texttt{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 ('\n');
	return 0;
}

~K Perm Counting

题目传送门

题目大意

如果一个排列 \(P\) 满足对于所有的 \(i\) 都有 \(|P_i-i|\not= k\),则称排列 \(P\) 为合法的。现给出 \(n\)\(k\),求有多少种合法的排列。

由于答案很大,请输出答案对 \(924844033\) 取模的结果。

\(n\le 2\times 10^3,k\le 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) \]

每个链的链头单独考虑即可。

\(\texttt{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 ('\n');
	return 0;
}
posted @ 2020-10-12 22:06  Dark_Romance  阅读(112)  评论(0编辑  收藏  举报