好难啊!
我的思路是用过河卒那样的加法原理算出1000*1000之内的两个点之间的距离,然后一个一个豆子来吃,吃到终点,方案数就乘法原理一个一个乘。
但是很不幸,评测的时候五颜六色,只有45pts。
正解是这样的:
你把人的坐标设为\((x,y)\),因为人只能往右或者下走,所以要不x来加1,要不y来加1。不管怎样他们的和都会+1。
所以我们搞个结构体,根据他们的坐标和从小到大排序。
然后就能一个点到一个点之间来算方案数。
这个方案数是多少呢?
设\(dx=x_i-x_{i-1},dy=y_i-y_{i-1}\),则局部方案数是\(C_{dx+dy}^{dx}\)或\(C_{dx+dy}^{dy}\)。
组合数就按照预处理阶乘,求逆元等步骤可以很快地单一搞出来。
所以这些东西相乘就是答案。
有个坑点:这些东西相乘的时候可能会在你没留意的时候爆int,所以还是long long保平安。昨晚因为这个调得我心态有点爆炸。
代码:
#include<cstdio>
#include<algorithm>
#define ll long long
const ll maxn = 300005;
const ll mod = 1e9 + 7;
struct Nodes
{
ll x, y;
} s[maxn];
ll frac[maxn];
ll n, m, k;
bool cmp(Nodes a, Nodes b)
{
return a.x + a.y < b.x + b.y;
}
ll exgcd(ll a, ll b, ll &x, ll &y)
{
if(b == 0){ x = 1; y = 0; return a; }
else
{
ll ret = exgcd(b, a % b, x, y);
ll t = x;
x = y;
y = t - a / b * y;
return ret;
}
}
ll inv(ll a)
{
// a * inv === 1 (mod p)
// a * inv - y * p = 1
ll x, y;
exgcd(a, mod, x, y);
return (x % mod + mod) % mod;
}
ll read()
{
ll ans = 0, s = 1;
char ch = getchar();
while(ch > ‘9‘ || ch < ‘0‘){ if(ch == ‘-‘) s = -1; ch = getchar(); }
while(ch >= ‘0‘ && ch <= ‘9‘) ans = (ans << 3) + (ans << 1) + ch - ‘0‘, ch = getchar();
return s * ans;
}
void init()
{
frac[0] = 1;
for(int i = 1; i <= 300000; i++) frac[i] = frac[i - 1] * i % mod;
}
ll C(ll m, ll n)
{
return frac[m] * inv(frac[n]) % mod * inv(frac[m - n]) % mod;
}
int main()
{
n = read(), m = read(), k = read();
s[1] = (Nodes){1, 1};
for(int i = 2; i <= k + 1; i++)
{
s[i].x = read(), s[i].y = read();
}
s[k + 2] = (Nodes){n, m};
k += 2;
std::sort(s + 1, s + k + 1, cmp);
ll ans = 1;
init();
for(int i = 2; i <= k; i++)
{
ll dx = s[i].x - s[i - 1].x;
ll dy = s[i].y - s[i - 1].y;
if(dx < 0 || dy < 0)
{
printf("0\n");
return 0;
}
//printf("%d %d\n", dx, dy);
ans = ans * C(dx + dy, dx) % mod;
}
printf("%lld\n", ans);
return 0;
}
原文:https://www.cnblogs.com/Garen-Wang/p/9813494.html