题目链接:登录—专业IT笔试面试备考平台_牛客网
题目:
样例输入:
1000000
样例输出:
270258012
分析:设Ai表示第i对cp相邻这个性质,那么我们就是要求N((1-A1)(1-A2)……(1-An)),先表示出i对cp相邻的数目,由于n对cp是没有区分的,所以我们可以选择任意i对cp表示其相邻,选取方案数是C(n,i),每对cp相邻我们就把他俩看成一个点,那么总共就是n*2-i个点,由于是排成环,那么我们需要以任意一个点作为头节点,其余点进行全排列即可,那么排列方案数就是(n-2*i-1)!,每对cp内部排列是任意的,所以就是两种情况,总共有i对cp,所以贡献就是2^i,再套上容斥原理公式即得:
这道题对时间和空间的要求都比较严格,所以必须要尽可能地优化,我下面附上未优化代码和优化后的代码供大家比对
未优化的代码(超时)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N=6e7+10,mod=1e9+7;
ll fac[N],inv[N];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
ll C(ll a,ll b)
{
return fac[a]*inv[b]%mod*inv[a-b]%mod;
}
int main()
{
ll n;
cin>>n;
if(n==1)
{
puts("0");
return 0;
}
fac[0]=inv[0]=1;
for(int i=1;i<=2*n;i++)
fac[i]=fac[i-1]*i%mod;
inv[2*n]=qpow(fac[2*n],mod-2);
for(int i=2*n-1;i>=1;i--)
inv[i]=inv[i+1]*(i+1)%mod;
ll ans=0;
int sign=1;
for(int i=0;i<=n;i++)
{
ans=(ans+sign*C(n,i)*fac[2*n-i-1]%mod*qpow(2,i))%mod;
ans=(ans+mod)%mod;
sign=-sign;
}
printf("%lld",ans);
return 0;
}
优化后代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
const int N=3e7+10,mod=1e9+7;
int inv[N];
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1) ans=ans*a%mod;
b>>=1;
a=a*a%mod;
}
return ans;
}
int main()
{
ll n;
cin>>n;
if(n==1)
{
puts("0");
return 0;
}
inv[0]=1;
for(int i=1;i<=n;i++)
inv[i]=1ll*inv[i-1]*i%mod;
inv[n]=qpow(inv[n],mod-2);
for(int i=n-1;i>=1;i--)
inv[i]=1ll*inv[i+1]*(i+1)%mod;
ll ans=0;
ll sign;
ll fac1=1,fac2=1,p2=1;
ll inv2=qpow(2,mod-2);//inv2记录2关于mod的逆元
//fac1记录fac[n],fact2记录fac[2*n-i-1],p2记录qpow(2,i)
for(int i=1;i<=n;i++) fac1=fac1*i%mod,p2=p2*2%mod;
for(int i=1;i<n;i++) fac2=fac2*i%mod;
if(n&1) sign=-1;
else sign=1;
for(int i=n;i>=0;i--)
{
// ans=(ans+sign*C(n,i)*fac[2*n-i-1]%mod*qpow(2,i))%mod;
ans=(ans+sign*fac1*inv[i]%mod*inv[n-i]%mod*fac2%mod*p2)%mod;
fac2=fac2*(2*n-i)%mod;
p2=p2*inv2%mod;
sign=-sign;
}
ans=(ans%mod+mod)%mod;
printf("%lld",ans);
return 0;
}