排列组合+逆元+快速幂

题目:

题解代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
ll inv[maxn];
//快速幂模板
ll qpow(ll a,ll b)
{
ll res=1;
while(b)
{
if(b&1)
res=res*a%mod;
a=a*a%mod;
b >>= 1;
}
return res;
}
//初始化,提前求出每个元素的逆元
void init()
{
inv[0]=1;
for(int i=1;i<maxn;i++)
{
inv[i]=inv[i-1]*qpow(i,mod-2)%mod;//求出每个数的阶乘的逆元
}
}
ll a[maxn];
int main()
{
init();
int n;
cin>>n;
ll sum=0;
for(int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
sum%=mod;
//可以发现,任意选四个点(处共线外)只有一种情况满足条件
//任意选四个点的所有情况
ll ans=sum%mod*(sum-1)%mod*(sum-2)%mod*(sum-3)%mod*inv[4]%mod;//Cn4(排列组合数),除以4!相当于乘以4!的逆元
for(int i=1;i<=n;i++)
{
//减去四点共线的情况
ll res=a[i]%mod*(a[i]-1)%mod*(a[i]-2)%mod*(a[i]-3)%mod*inv[4]%mod;
ans-=res;
ans=(ans%mod+mod)%mod;//上一步可能出现负数情况,给他加回来
//减去三点共线的情况
res=a[i]%mod*(a[i]-1)%mod*(a[i]-2)%mod*(sum-a[i])%mod*inv[3]%mod;
ans-=res;
ans=(ans%mod+mod)%mod;
//加上两点重合的情况
res=a[i]%mod*(sum-a[i])%mod*(sum-a[i]-1)%mod*inv[2]%mod;
ans+=res;
ans=(ans%mod+mod)%mod;
}
cout<<ans*2%mod<<endl;//红线和紫线可以交换,所以*2,即每四个点都对应两种情况
return 0;
}

 

posted @ 2024-05-24 20:13  萌墨  阅读(48)  评论(0)    收藏  举报