zoukankan      html  css  js  c++  java
  • 刷题总结——分糖(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;
    }

      

  • 相关阅读:
    Ansible安装配置
    Git 工作流程
    使用 Docker 搭建 Tomcat 运行环境
    Linux的cron与%
    配置sonar和jenkins进行代码审查
    Jenkins配置基于角色的项目权限管理
    Jenkins和maven自动化构建java程序
    Jenkins修改workspace和build目录
    Git 进阶指南
    git代码回滚:Reset、Checkout、Revert的选择
  • 原文地址:https://www.cnblogs.com/AseanA/p/7634532.html
Copyright © 2011-2022 走看看