【洛谷P3414】 SAC#1 - 组合数

题目背景

本题由世界上最蒟蒻最辣鸡最撒比的SOL提供。

寂月城网站是完美信息教室的官网。

题目描述

辣鸡蒟蒻SOL是一个傻逼,他居然觉得数很萌!

今天他萌上了组合数。现在他很想知道simga(C(n,i))是多少;其中C是组合数(即C(n,i)表示n个物品无顺序选取i个的方案数),i取从0到n所有偶数。

由于答案可能很大,请输出答案对6662333的余数。

输入输出格式

输入格式:

 

输入仅包含一个整数n。

 

输出格式:

 

输出一个整数,即为答案。

 

输入输出样例

输入样例#1:
3
输出样例#1:
4

说明

对于20%的数据,n <= 20;

对于50%的数据,n <= 1000;

对于100%的数据,n <= 1 000 000 000 000 000 000 (10^18)

题解:

关于二项式定理的的知识可浏览360百科中的:https://baike.so.com/doc/5409658-5647689.html

由二项式定理可得:C(n,0)+C(n,1)+C(n,2)+…+C(n,n-2)+C(n,n-1)+C(n,n)=2^n

由于题目上说i只取偶数(包括0)所以最后的结果是2^(n-1)。

用O(n)算法效率低会超时的。

剩下的就是快速幂了,可以用迭代写,也可以用递归,那得看个人习惯了。

快速幂用位运算写效率可能更高:

这是百度百科中比较好的快速幂位运算算法:

int pow(int a,int b){
  int r=1,base=a;
  while(b){
    if(b&1) r*=base;
    base*=base;
    b>>=1;
  }
  return r;
}

百度百科中关于快速幂的讲解比较详细:https://baike.baidu.com/item/%E5%BF%AB%E9%80%9F%E5%B9%82

本题在做的过程中要取余,下面贴出个人代码:

 

递归:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll n;
ll powmod(ll k,ll m)
{
    if(k==0) return 1;
    ll x=powmod(k/2,m);
    ll ans=(x*x)%m;
    if(k%2) ans=(ans*2)%m;
    return ans;
}
int main()
{
    scanf("%lld",&n);
    ll ans=powmod(n-1,6662333);
    printf("%lld\n",ans);
    return 0;
}

非递归:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
ll n;
ll powmod(ll a,ll b,ll c)
{
    ll ans=1%c; a%=c;
    while(b)
    {
        if(b%2==1) ans=ans*a%c;
        b=b/2; a=a*a%c;
    }
    return ans;
}
int main()
{
    scanf("%lld",&n);
    ll ans=powmod(2,n-1,6662333);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2017-07-17 23:20  沐灵_hh  阅读(214)  评论(0编辑  收藏  举报