CF——#178 div2C(数论)

题目地址:http://codeforces.com/contest/294/problem/C

解析参考地址:http://hi.baidu.com/zyz913614263/item/796b1a7c8bda6405d0dcb30c

关键就是求(n-k)!/(x!*y!……*z!  )*2^(m-1),我是直接把阶乘分解成质因子的,然后相减,再求次方,然后相乘求解。(具体见代码。)

注:这种方法是自己想出来的奥,不过仅仅适合数据比较小的时候,不然会超时,比如在做CF#181 div2C的时候就不可以用这种方法了。

源代码:

#include <iostream>
#include <algorithm>
#include <string.h>
#include <cmath>
#include <stdio.h>
using namespace std;
int b[10005];
#define MOD  1000000007
int a[1005];//存储上面的分解 
int c[1005];//存储下面的分解 
int prime[1100];
int flag[1100];
int ans[1005];
void init()
{
memset(flag,0,sizeof(flag));
int q=0;
for(int i=2;i<1100;i++)    //注意要求到比1000大的一个质数,作为后来结束的标志(在这runtime error了次
)

{
if(!flag[i])
   {
            prime[q++]=i;
for(int j=i+i;j<1100;j+=i)
 flag[j]=1;
   }
}
}
void fun1(int k)      //求上面(n-k)!的分解情况
{
for(int i=0;k>=prime[i];i++)
{
int j=prime[i];
int num=0;
while(k>=j)
{
num+=k/j;
j*=prime[i];
}
a[prime[i]]+=num;
}
}
void fun2(int k)   //求下面的分解情况
{
for(int i=0;k>=prime[i];i++)
{
int j=prime[i];
int num=0;
while(k>=j)
{
num+=k/j;
j*=prime[i];
}
c[prime[i]]+=num;
}
}
long long Pow(int x,int y)   //求x^y%MOD
{
if(y==0) return 1;
long long mid=(long long)x;
    while(y>1)
    {
    mid=(mid*x)%MOD;
    y--;
    }
    return mid%MOD;
}
int main()
{
int m,n;
int t,i,j,k,l;
int num;
        init();
while(cin>>n>>k)
{
  memset(a,0,sizeof(a));
  memset(c,0,sizeof(c));
    
  for(i=0;i<k;i++)   cin>>b[i];
  sort(b,b+k);
  fun1(n-k);
  
  if(b[0]>2) fun2(b[0]-1);   //求两端的特殊情况。
    
  if(b[k-1]<n-1) fun2(n-b[k-1]);


  for(i=1;i<k;i++)    //中间的情况,这是要加上2^(mid-1)

          {
         int mid=b[i]-b[i-1]-1;
 if(mid<=1) continue;
 else 
 {
  fun2(mid);
        a[2]+=(mid-1);
 }
          }
          for(i=0;prime[i]<=n-k;i++)
          {
          ans[prime[i]]=a[prime[i]]-c[prime[i]];
          }
          long long re=1;
          for(i=0;prime[i]<=n-k;i++)
          {
          re=(re*Pow(prime[i],ans[prime[i]]))%MOD;
          }
          cout<<re<<endl;
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值