快速乘法-快速幂

来源:互联网 发布:广州软件开发培训 编辑:程序博客网 时间:2024/04/28 03:13
Description
从 n 个不同元素中任取 m(m≤n)个元素,按照一定的顺序排列起来,叫做从 n
个不同元素中取出 m 个元素的一个排列。当 m=n 时所有的排列情况叫全排列。
你觉得 xxy 会问你全排列的个数吗?Xxy:这个问题能淹死你,我才不问呢。我
要问的是求 n 的全排列中,先递增后递
减、先递减后递增的全排列的个数。由于答案可能很大,对 p 取余
Input
输入包含多组测试数据每组测试
数据一行两个整数 n,p
Output
对于每组测试数据输出一行表示答案
3 5

4
2 233

0
Hint
设数据组数为 T
对于 10%的数据,n<=10,p<=1000,T=1
对于另外 10%的数据,n<=12,p<=1000,T<=12
对于另外 10%的数据,n<=100,p<=100000,T<=100
对于另外 10%的数据,n<=100000,p<=1000000,T=1
对于另外 10%的数据,n<=100000,p<=1000000,T<=1000
对于另外 20%的数据,n<=1e9,p<=1e9,T<=1000
对于 100%的数据,n<=1e18,p<=1e18,T<=1000

 

找规律 

对于3 我们可以找出所有情况 

1 3 2

2 3 1

2 1 3

3 1 2

我们可以发现 4的所有递增递减的情况一定是基于3的所有情况 

 1 3 2   我们可以将4放在 3前面 1 4 3 2 或者 放在3后面 1 3 4 2 

其他情况相同 n全排列的单峰情况 一定可以由n-1的单峰排列情况推出 

共2的n次方种

但这不是全部  

还有特殊情况 1 2 3  -->1 2 4 3

          -->4 1 2 3   

       3 2 1  -->3 4 2 1

          -->3 2 1 4   

共 2n+4种

2n用快速幂和快速乘即可

 

 1 #include <cstdio> 2 #include <cctype> 3 #include <algorithm> 4  5 typedef long long LL; 6  7 using namespace std; 8  9 int T;10 11 LL n,p;12 13 inline void read(LL&x) {14     int f=1;register char c=getchar();15     for(x=0;!isdigit(c);c=='-'&&(f=-1),c=getchar());16     for(;isdigit(c);x=x*10+c-48,c=getchar());17     x=x*f;18 }19 20 inline LL quick_plus(LL b,LL k) {21     LL ans=0;22     while(k) {23         if(k&1) ans=(ans+b)%p;24         k>>=1;25         b=(b+b)%p;26     }27     return ans%p;28 }29 30 inline LL quick_pow(LL a,LL k) {31     LL ans=1;32     while(k) {33         if(k&1) ans=quick_plus(ans,a);34         k>>=1;35         a=quick_plus(a,a);36     }37     return ans;38 }39 40 int hh() {41 //    freopen("permutation.in","r",stdin);42 //    freopen("permutation.out","w",stdout);43     while(~scanf("%lld%lld",&n,&p)) {44         if(n==1||n==2) {45             printf("0\n");46             continue;47         }48         LL ans=quick_pow(2,n);49         LL L=4-p;50         ans=(ans-L+p)%p;51         printf("%lld\n",ans);52     }53     return 0;54 }55 56 int sb=hh();57 int main(int argc,char**argv) {;}
代码