zoukankan      html  css  js  c++  java
  • 2020-10-12 集训题目题解

    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;
    }
    
  • 相关阅读:
    code of C/C++(2)
    code of C/C++ (1)
    dll 的编写和使用
    Python基础练习-数据类型与变量part2
    Python基础练习-数据类型与变量
    python基础练习-循环
    Linux grep
    nginx反向代理
    正则表达式
    Linux samba ing
  • 原文地址:https://www.cnblogs.com/Dark-Romance/p/13805900.html
Copyright © 2011-2022 走看看