P1866 编号
一、题意解析
每只兔子的喜好整数范围不一样,有的大,有的小。想求方案的总数量,就是所有的可行方案解数。
所有方案解,就是所有可能,不能丢失某种情况。
那么,如何才能不丢失情况呢?就是最全的,也可以理解为最多的。
咋能最多呢?如果让兔子们随便挑选,肯定完蛋了~,所以,需要让他们有“秩序”的选择,而这个秩序,就是我们解题的关键。
什么秩序呢?就是猜一个你认为对的顺序,然后再证明它的正确性。
其实,贪心这玩意,无外乎先猜由小到大,再猜最大到小,再猜a+b,不行,再猜a-b,balabalabala...
先猜一下按号码由小到大,那就是范围小的先来,范围大的后来。以\([8,3,5,6]\)为例,就是先让范围为\(3\)的先来,有\(3\)种,\(5\)的后来,因为前面占了一种,所以是\(4\)种,...
\(s=3*(5-1)*(6-2)*(8-3)=240\)种。
下面来简单证明一下这种方法的正确性。
极限思维法,假设\(a,b\)是两只兔子的喜好整数。那么
\(sum1=a*(b-1)\)
\(sum2=b*(a-1)\)
讨论一下\(sum1\)和\(sum2\)的大小关系:
\(sum1-sum2=a*b-a-a*b+b=b-a\)
也就是说,如果\(b-a>0\),\(sum1>sum2\),换句人话来说就是\(b>a\)可以使得结果更大,即\(a,b\)按从小到大排序即可。
两个是这样的情况,那么多个呢?多个可以视为多组两个,每两个都由小到大,自然就是一个排序的意思了~
二、关键点
1、贪心策略的选择和证明
2、同余定理
\((a+b+c)\%k=((a+b)\%k+c)\%k\)
\((a*b*c)\%k=((a*b)\%k*c)\%k\)
三、完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1000000007;
const int N = 51; //50只兔子是上限值
int n; //具体是几只兔子
int num[N]; //字牌编号
int main() {
LL ans = 1;
cin >> n;
for (int i = 1; i <= n; i++)cin >> num[i];
sort(num + 1, num + 1 + n);//排序,贪心
for (int i = 1; i <= n; i++) {
ans *= (num[i] - i + 1);
ans %= MOD; //边乘边模,使用了同余定理
}
//输出结果
cout << ans << endl;
return 0;
}