枚举 组合数 P3799 妖梦拼木棒

P3799 妖梦拼木棒 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路:可以发现对于 n n n来说是1e5, O ( n 2 ) O(n^2) O(n2)算法不行,但是发现对于每一个 a i a_i ai来说,都是**小于5e3的正整数。**对此,我们可以考虑枚举1到5e3进行计算。

对于四个棍子要形成一个正三角形来说,一定是有两个棍子是相同的,剩下两个棍子累加等于之前的棍子,即对于i,j,k,z四个棍子来说,当且仅当 i = j i = j i=j k + z = i k + z = i k+z=i时才能形成一个正三角形。

从1到5e3枚举两根棍子相同的情况,之后在找剩下两个棍子相加等于该棍子的情况,此时是 C c n t 2 C_{cnt}^2 Ccnt2

对此,有两种情况:

  • k = = z k == z k==z :这时计算是 C v 2 C_{v}^2 Cv2
  • k ! = z k != z k!=z:这时计算是 n u m k ∗ n u m z num_{k} * num_{z} numknumz

根据情况进行相乘并取模即可。计算时有除法操作,需要逆元。

代码如下:

const int mod = 1e9 + 7;
LL inv(LL a) {
    if(a == 0 || a == 1) return a;
    return (mod - mod/a) * inv(mod % a) % mod;
}
void solve() {
	int n; cin>>n;
	vector<int> a(5021);
	for(int i = 0; i < n ;++i) {
		int t; cin>>t;
		a[t]++;
	}
	int ans = 0;
	for(int i = 2; i <= 5000; ++i) {
		if(a[i] < 2) continue;
		int pre = (a[i] % mod* (a[i] - 1) % mod *inv(2)) % mod;;
		for(int j = 1; j <= i / 2; ++j) {
			if(j != i - j && a[j] > 0 && a[i - j] > 0) {
				int t = pre * a[j] % mod * a[i - j] % mod;
				ans = (ans + t) % mod;
			}
			if(j == i - j && a[j] > 1) {
				int t = pre * (a[j] % mod* (a[j] - 1) % mod *inv(2) % mod);
				ans = (ans + t) % mod;
			}
		}
	}
	cout<<ans<<endl;
}

你可能感兴趣的:(算法题,算法,c++,数据结构)