题解
我们考虑什么时候连个球能进行交换。
显然如果有三个球
于是我们可以把
由于不同颜色与相同颜色交换条件是不一样的,我们先考虑相同颜色。
显然只需要用最小值做“媒介”即可。
然后我们考虑跨颜色交换。我们发现只需要用全局最小值做“媒介”,也就是说对于某个点,先通过该颜色最小值换到全局最小值,再通过全局最小值换到其他点。如果与全局最小值颜色相同,那我们就只能用次小值做媒介。
这样我们只需要记录某种颜色的最小值、全局最小值、全局次小值即可。
然后我们不难发现含有不同颜色的连通块只有一个,那就是全局最小值所在的连通块。
而只有一种颜色的连通块对答案没有影响。
于是我们只考虑最小值所在的连通块。首先我们找到全局最小值、全局次小值与每种颜色的最小值。如果他们都不能交换,那显然是凉了(答案为
代码
cpp
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 1000005;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
int n, A, B;
int fac[maxn], inv[maxn];
int c[maxn], w[maxn], minci[maxn];
int Gs[maxn];
inline int pow(int a, int b)
{
int ans = 1;
for(; b; b >>= 1, a = (LL) a * a % mod)
if(b & 1)
ans = (LL) ans * a % mod;
return ans;
}
inline int C(int n, int m)
{
if(!n)
return 1;
if(m < n)
return 0;
return (LL) fac[m] * (LL) inv[m - n] % mod * (LL) inv[n] % mod;
}
int main()
{
scanf("%d%d%d", &n, &A, &B);
memset(minci, 0x3f, sizeof(minci));
for(int i = 1; i <= n; ++i)
{
scanf("%d%d", &c[i], &w[i]);
minci[c[i]] = min(minci[c[i]], w[i]);
}
int minn = 0, minnn = 0;
for(int i = 1; i <= n; ++i)
{
if(minci[i] < minci[minn])
{
minnn = minn;
minn = i;
}
else if(minci[i] < minci[minnn])
minnn = i;
}
int gss = 0;
for(int i = 1; i <= n; ++i)
{
if(w[i] + minci[c[i]] <= A)
w[i] = minci[c[i]];
if(c[i] == minn && minci[minnn] + w[i] <= B)
{
Gs[c[i]]++;
gss++;
}
if(c[i] != minn && minci[minn] + w[i] <= B)
{
Gs[c[i]]++;
gss++;
}
}
int ans = 1;
fac[0] = 1;
for(int i = 1; i <= n; ++i)
fac[i] = (LL) i * fac[i - 1] % mod;
inv[n] = pow(fac[n], mod - 2);
for(int i = n - 1; ~i; --i)
inv[i] = (LL) inv[i + 1] * (i + 1) % mod;
for(int i = 1; i <= n; ++i)
{
if(Gs[i])
{
ans = (LL) ans * (LL) C(Gs[i], gss) % mod;
gss -= Gs[i];
}
}
printf("%d\n", ans);
return 0;
}