首页 写随笔

cdcq(本博客废弃!现用博客:https://www.cnblogs.com/cdcq/)

本博客废弃!现用博客:https://www.cnblogs.com/cdcq/

导航

Asm.Def点大兵

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

 

posted on 2016-11-09 15:28  cdcq_old  阅读(289)  评论(0编辑  收藏  举报