首页 > 其他分享 >AT5169 Candy Retribution

AT5169 Candy Retribution

时间:2022-09-26 16:56:58浏览次数:46  
标签:AT5169 Retribution ch inv int sum Candy iy LL

题号是洛谷题号。

前置知识:\(\sum_{i=1}^{n}a_i=m\),\(\{a_n\in N^*\}\) 方案数为 \(C_{n+m-1}^{n-1}\),\(\sum_{i=1}^{n}a_i\ge m\) 方案数为 \(C_{n+m}^{n}\),后一项的证明就是考虑有 \(n\) 个隔板和 \(m\) 个物体隔板,然后隔出来有 \(n+1\) 个物品,最后一项物品舍弃掉即可。

设 \(\{a_n\}\) 降序排列后为 \(\{b_n\}\),要统计 \(b_m=b_{m+1}\) 不好统计,因为你不知道 \(b_m\) 有多少个,但是可以统计 \(b_m>b_{m+1}\) 即非法序列个数。

首先将 \(\sum a_i\in[L,R]\) 弱化成 \(\sum a_i\le R\),就是差分一下 Solve(R)-Solve(L-1)

枚举 \(b_m\) 的值 \(x\),设 \(f(s,x,y)\) 表示当前序列总和小于等于 \(s\),\(m\) 个数大于等于 \(x\),剩余 \(n-m\) 个数小于 \(x\) 的方案数,那么 \(b_m=x\) 时这一块的非法序列个数就是 \(f(s,x,x)-f(s,x+1,x)\)。

考虑如何求 \(f(s,x,y)\),先选 \(m\) 个位置作为 \(\ge x\) 的位置,剩余 \(n-m\) 位置小于 \(y\),但是注意到隔板法不好求对每个数上界和下界(非 0)有限制的方案数,于是考虑容斥,枚举 \(i\in [0,n-m]\) 表示 \(n-m\) 个位置中至少有 \(i\) 个位置 \(>=y\),将这 \(i\) 个位置和之前的 \(\ge x\) 的数全部从和当中减掉,新和就是 \(s-mx-iy\),然后又要求减掉后的序列和小于等于 \(s-mx-iy\),于是有:

\[f(s,x,y)=C_n^m\sum_{i=0}^{n-m}(-1)^iC_{n-m}^{i}C_{s-mx-iy+n}^n \]

因此最后非法序列个数就是 \(\sum_{x=1}^{m}f(s,x,x)-f(s,x+1,x)\),总序列个数 \(C_{n+s}^{n}\) 减去即可。

由于要求 \(s-mx-iy\ge0\),而 \(iy\) 成倍数增长,所以实际复杂度为调和级数。

Code:

/*
========= Plozia =========
	Author:Plozia
	Problem:AT5169 Candy Retribution
	Date:2022/9/25
========= Plozia =========
*/

#include <bits/stdc++.h>
#define int long long
typedef long long LL;

const int MAXN = 6e5 + 5;
const LL P = 1e9 + 7;
int n, m, l, r;
LL fact[MAXN], inv[MAXN];

int Read()
{
	int sum = 0, fh = 1; char ch = getchar();
	for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
	for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = (sum << 3) + (sum << 1) + (ch ^ 48);
	return sum * fh;
}
LL ksm(LL a, LL b = P - 2, LL p = P)
{
	LL s = 1 % p;
	for (; b; b >>= 1, a = a * a % p)
		if (b & 1) s = s * a % p;
	return s;
}
LL C(LL n, LL m) { return fact[n] * inv[m] % P * inv[n - m] % P; }

LL f(int x, int y, int s)
{
	LL sum = 0;
	for (int i = 0; i <= n - m; ++i)
	{
		if (1ll * s - m * x - i * y < 0) return sum * C(n, m) % P;
		sum = (sum + ((i & 1) ? -1 : 1) * C(n - m, i) * C(1ll * s - m * x - i * y + n, n) % P) % P;
		sum = (sum + P) % P;
	}
	return sum * C(n, m) % P;
}

LL Solve(int s)
{
	LL sum = 0;
	for (int i = 1; i <= s; ++i)
		sum = ((sum + f(i, i, s) - f(i + 1, i, s)) % P + P) % P;
	return (C(s + n, n) % P - sum + P) % P;
}

signed main()
{
	n = Read(), m = Read(), l = Read(), r = Read();
	fact[0] = 1; for (int i = 1; i <= 600000; ++i) fact[i] = fact[i - 1] * i % P;
	inv[600000] = ksm(fact[600000]); for (int i = 599999; i >= 0; --i) inv[i] = (i + 1) * inv[i + 1] % P;
	printf("%lld\n", ((Solve(r) - Solve(l - 1)) % P + P) % P); return 0;
}

标签:AT5169,Retribution,ch,inv,int,sum,Candy,iy,LL
From: https://www.cnblogs.com/Plozia/p/16731510.html

相关文章