Asm.Def点大兵

介绍了一种在处理大数排列求模问题时使用的高效算法。该算法通过二进制分配乘法避免了直接使用longlong类型导致的溢出问题,并提供了一个具体的C++实现示例。

syzoj上的题,收货很多,orz天天学长

原题:

Asm.Def奉命组建一支m人的特种作战小队前往圣迭戈。他有n名候选人,可以在其中任意挑选。由于小队中每个人都有独特的作用,所以次序不同的两种选法被认为是不同的方案。由于方案数可能非常大,Asm.Def只需要知道它模p的值。

100%:n<=10^18,m<=10^5,p<=10^18

 

很明显就是求排列……

然而n<=10^18用longlong乘的话会炸

用高精度的话取模会非常不好搞,而且常数似乎也不滋瓷

syzoj可以直接查看别人代码,然后就看到了这么个黑科技:

 1 LL f(LL x,LL y)
 2 {
 3     LL tmp=0;
 4     while(y)
 5     {
 6         if(y&1)
 7             tmp=(tmp+x)%p;
 8         y=y>>1;
 9         x=(x<<1)%p;
10     }
11     return tmp;
12 }
View Code

一眼看上去挺像快速幂的,看不懂,请教天天学长

然后就知道这是为了防止炸longlong的二进制分配乘

原理就是将其中一个乘数分解成二进制,比如5 * 17就是5 * (16 + 1),5 * 23 就是 5 * (16 + 4 + 2 + 1)

逐步膜就不会炸longlong

新姿势get√

还要再强调一下,如果使用longlong就要逐步走一遍,所有遇到的变量全部换成longlong,尤其是函数的参数和返回值,有时候甚至循环变量也会使用longlong,比如for(long long i=n-m+1;i<=n;i++),其中n,m都是longlong

代码:

 1 //__3_108_120_116__
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cmath>
 7 using namespace std;
 8 long long m,n,mo;
 9 long long ans=1;
10 long long multiply01(long long x,long long y){//参数传的是longlong!!!
11     long long z=0;
12     while(y){
13         if(y&1)  z=(z+x)%mo;
14         y=y>>1;
15         x=(x<<1)%mo;
16     }
17     return z;
18 }
19 int main(){
20     cin>>n>>m>>mo;
21     for(long long i=n-m+1;i<=n;i++)//要注意这里n会很大所以i要longlong!
22         ans=multiply01(ans,i);
23     cout<<ans<<endl;
24     return 0;
25 }
View Code

 

转载于:https://www.cnblogs.com/JSL2018/p/6047137.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值