AtCoder Beginner Contest 156 比赛人数7003
AtCoder Beginner Contest 156 D Bouquet 失之交臂 容斥原理+二项式定理+乘法逆元+快速幂+模后负数 多余担心
总目录详见https://blog.csdn.net/mrcrack/article/details/104454762
在线测评地址https://atcoder.jp/contests/abc156/tasks/abc156_d
容斥原理+二项式定理+乘法逆元+快速幂+模后负数
算了第一组数据
C(4,2)=6,C(4,4)=1,ans=6+1=7
还可以这样算
C(4,0)+C(4,1)+C(4,2)+C(4,3)+C(4,4)-C(4,1)-C(4,3)-C(4,0)
=2^4-C(4,1)-C(4,3)-1
=16-4-4-1
=7
但是,一直担心2≤n≤10^9在算n!时会超时,想过卢卡斯定理,但是很遗憾modulo (10^9+7)
马上切换到下一题E,解决了E中大半问题,被卡住了,又重新切换回来。
很快编好,死马当活马医,提交,担心的是没有发生,没有超时,但又WA,看啦看只有一组数据出错,
收获n=10^9,n!的计算,既然消耗不到1s,打破了10^6-10^7需消耗1s的认知。多余担心
哪错了呢,看看题目,扫扫代码,没有问题啊。
比赛结束后,马上就想到了,还是 模后可能遇到负数,如何处理成正数,
ans=(ans%mod+mod)%mod;//错写成ans=(ans+mod)%mod;
修改,提交,立马AC.失之交臂.教训,考虑到的细节,还是要在代码中仔细看看,是否能精确的实现。
#include <stdio.h>
#define mod 1000000007
#define LL long long
LL n,a,b;
LL quick_pow(LL a,LL b){
LL ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
LL C(LL a,LL b){
LL i,ans=1,c=1;
for(i=a;i>=a-b+1;i--)ans=ans*i%mod;
for(i=b;i>=1;i--)c=c*i%mod;
return ans*quick_pow(c,mod-2)%mod;
}
int main(){
LL ans=0;
scanf("%lld%lld%lld",&n,&a,&b);
ans+=quick_pow(2,n)-1;//全集
ans-=C(n,a);
ans-=C(n,b);
ans=(ans%mod+mod)%mod;//错写成ans=(ans+mod)%mod;
printf("%lld\n",ans);
return 0;
}