刷题总结——分糖(ssoj 容斥原理+逆元+快速幂+组合数求插板)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了刷题总结——分糖(ssoj 容斥原理+逆元+快速幂+组合数求插板)相关的知识,希望对你有一定的参考价值。

题目:

题目描述

有 N 个(相同的)糖果,M 个(不同的)小朋友。M 和 N 满足:1≤M≤N≤100000(105)。
要求:
1.每个小朋友都至少有一个糖果。
2.不存在正整数 X(X>=2),使得每个小朋友的糖果数都是 X 的倍数。
3.糖果不能剩余。
求分糖方法总数。答案模 1000000007(109+7)

输入格式

第一行为数据组数:T<=100000。
接下来 N 行,每行 2 个如上文所示的正整数 N,M。

输出格式

输出 T 行,每行一个整数,为答案。
注意取模!

样例数据 1

输入  [复制]

 

 


6 2 
7 2 
6 3 
6 4 
7 4

输出




10 
20

备注

【数据范围】
对于 30% 的数据:1<=M<=N<=20
对于 60% 的数据:1<=M<=N<=1000
对于 100% 的数据:1<=M<=N<=100000

题解:

  一道题充分证明我在数论上是个sb

  首先第一次学到用dfs来求充斥,涨姿势了····

  然后就是用组合数来解决将x个糖分到y个小朋友手里的问题····相当于在x-1个空格中插入y-1个板子···转化成组合数···

  最后一个问题就是组合数每次肯定只能通过预处理的阶乘相处来求··然而阶乘已经取模···相当于如何计算a/bmodp的问题····

  不难想到a/b相当于a*1/b,而1/b%p就是b模p的逆元····且p为质数的情况下逆元直接等于b的p-2次方模p,用快速幂来求即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
using namespace std;
const int N=1e5+5;
const int mod=1e9+7;
vector<int>zhiyinzi[N];
long long jc[N],T,n,m,ans,niyuan[N];
bool notprime[N];
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<0||c>9;c=getchar());
  for(;c<=9&&c>=0;c=getchar())
    f=(f<<3)+(f<<1)+c-0;
  return f;
}
inline long long ksm(long long a,long long b)
{
  long long temp=1;
  while(b)
  {
    if(b%2==1)  temp=(temp*a)%mod;
    b/=2;
    a=(a*a)%mod;
  }
  return temp;
}
inline void pre()
{
  for(int i=2;i<=100000;i++)
  {
    if(!notprime[i])
    {
      zhiyinzi[i].push_back(i);  
      for(int j=2;j*i<=100000;j++)
      {  
        notprime[i*j]=true;
        zhiyinzi[i*j].push_back(i);
      }
    }
  }
  jc[0]=1;  
  for(int i=1;i<=100000;i++)  jc[i]=(jc[i-1]*i)%mod; 
  for(int i=0;i<=100000;i++)  niyuan[i]=ksm(jc[i],mod-2);
}
inline int calc(int a,int b)
{
  if(a<b)  return 0;
  return ((long long)(jc[a-1]*niyuan[b-1])%mod*niyuan[a-b])%mod;
}
inline void dfs(int u,int tot,int f)
{
  if(u==zhiyinzi[n].size())
  {
    ans=(ans+f*calc(n/tot,m))%mod;
    return;
  }
  dfs(u+1,tot*zhiyinzi[n][u],-f);
  dfs(u+1,tot,f);
}
int main()
{
  //freopen("a.in","r",stdin);
  pre();T=R();
  while(T--)  {
    ans=0;n=R(),m=R();
    dfs(0,1,1);
    cout<<(((ans%mod)+mod)%mod)<<endl;
  }
  return 0;
}

 

  




















以上是关于刷题总结——分糖(ssoj 容斥原理+逆元+快速幂+组合数求插板)的主要内容,如果未能解决你的问题,请参考以下文章

快速幂运算+快速幂求乘法逆元

刷题总结——array(ssoj)

[数论+模板] 快速幂及快速幂求逆元算法模板(模板)

刷题总结——保留道路(ssoj)

刷题总结——art2(ssoj)

刷题总结——道路覆盖(ssoj)