您的位置:首页 > 其它

山东省第八届ACM省赛C firework

2017-07-23 20:29 302 查看
题目

题意:在数轴上会有烟花,他会向前一个和后一个扩散,然后在一定时间后,要求最后位置有多少烟花。

模拟一下发现一行中把0去掉之后他就是一个杨辉三角。新知识:杨辉三角就是组合数。但是因为组合数太大了,而且太慢了,所以要用乘法逆元。乘法逆元有好多种解法。这里用费马小定理。然后要考虑要求的点和烟花点的距离。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int fcnt=100005;
const long long mod=1000000007;
long long fac[fcnt];
void getfac()
{
fac[0]=1;
for(int i=1;i<fcnt;i++)
fac[i]=fac[i-1]*i%mod;
}
long long quickpow(long long a,long long b)
{
if(b<0)return 0;
long long ret=1;
a%=mod;
while(b)
{
if(b&1)
ret=(ret*a)%mod;
b>>=1;
a=(a*a)%mod;
}
return ret;
}
long long inv(long long a)
{
return quickpow(a,mod-2);
}
long long c(long long n,long long m)
{
if(n<m)
return 0;
return fac
*inv(fac[m])%mod*inv(fac[n-m])%mod;
}
int main()
{
long long int t,n,m;
getfac();
while(~scanf("%lld %lld %lld",&t,&n,&m))
{
long long ans=0;
for(int i=1;i<=t;i++)
{
long long int t1,t2;
scanf("%lld %lld",&t1,&t2);
if((t1-m+n+1)%2==0)//观察可得,第偶数个点一定是0
{
continue;
}
ans=(ans+(t2*c(n,(abs(t1-m)+n)/2))%mod)%mod;//第奇数个点-1然后除以二就是组合数的m,这里要注意绝对值。
}
printf("%lld\n",ans);
}
}


顺便补一个卢卡斯的用法(从师哥那里搬来的)

Lucas定理(大部分情况 p<105)

Cmn%p=(Cm%pn%p%p∗Cm/pn/p%p)%p

且C0n=1;

这样我们就可以用逆元法求出Cm%pn%p,然后递归求解Cmn%p

Lucas定理模板(C(m,n)代表Cmn)

long long Lucas(long long n,long long m)
{
if(m==0)
return 1;
return Lucas(n/p,m/p)*C(n%p,m%p)%p;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  acm