• 萌萌哒哒的2233娘~~~~


    本文为博主原创文章,欢迎转载,请注明出处 www.cnblogs.com/yangyaojia

    [SDOI2008]沙拉公主的困惑 线性筛 素数+欧拉

    题目大意

    给定n,m,求在1到n!内与m!互质的个数,答案要对r取模。

    输入格式:
    第一行为两个整数T,R。R<=10^9+~~10,T<=10000,表示该组中测试数据数目,R为模 后面T行,每行一对整数n,m,见题目描述 m<=n

    输出格式:
    共T行,对于每一对N,M,输出1至N!中与M!素质的数的数量对R取模后的值

    输入输出样例
    input
    1 11
    4 2
    output
    1

    解题分析
    首先,我们来引出一个定理
    如果a与b互质,那么(b*k+a)也与b互质。证明和证明gcd的证明类似。
    反过来,我们也可以用(gcd)证明,
    因为(gcd(a,b)=1),所以(gcd(a\%b,b)=1)
    因为(a\%b=a-k*b),故(gcd(a-k*b,b)=1),及(a-k*b)(b)互质。
    根据这个特性,并且(n>=m),所以可以将n!分成若干段,每段为m!,每一段中与m!互质的个数都是相等的且等于1到m!中与m!互质的个数
    我们可以得到式子

    (ans={frac{n!}{m!}*phi(m!)})

    进一步拆开,我们可以得到 (假设p为m!的质因数,很容易可以知道,p就是所有小于m的素数,r为质因数个数)

    (ans={frac{n!}{m!}*m!*frac{prod limits_{i=1}^{r}(p_i-1)}{prodlimits_{i=1}^{r}p_i } o ans=n!*frac{prod limits_{i=1}^{r}(p_i-1)}{prodlimits_{i=1}^{r}p_i } })

    因为(ans)(mod R),所以我们也要算1到m的逆元,在累乘$prodlimits_{i=1}^{r}p_i (,乘的是)p_i (的逆元。 有多组询问,我们得先预处理一些数据,累乘的时候要%R 我们令)k[i] = i! ,inv[i]为i的逆元,(f1[i]= {prodlimits_{a=1}^{i}(p_a-1)})
    $ ,f2[i]={prodlimits_{a=1}^{i}p_a} ( )ans=f1[m]f2[m]k[n]$
    先预处理O()答案,对于询问O(1)出解

    #include <cstdio>
    #include <iostream>
    #include <math.h>
    using namespace std;
    const int MAXN=10000000+10;
    bool su[MAXN];
    int q[MAXN][2],maxm,maxn,t,inv[MAXN],p,n,m;
    int k[MAXN],f1[MAXN],f2[MAXN],ans=0;
    void work()
    {
      
      inv[1]=1;k[1]=1;f1[1]=1;f2[1]=1;
      for(int i=2;i<=sqrt(maxm);i++) if(!su[i])
        for(int j=2;j<=maxm/i;j++) su[i*j]=1;
    
    	for(int i=2;i<=maxn;i++)
      {
      	if(i<=maxm) 
        {    
      	  inv[i]=(1LL*-(p/i)*inv[p%i])%p;
          inv[i]=(inv[i]%p+p)%p;
        }
          if(i<=maxm) 
      	  {
        	  if(!su[i])
            {
    	        f1[i]=(1LL*f1[i-1]*((i-1)%p))%p;
              f2[i]=(1LL*f2[i-1]*(inv[i]%p))%p;    
            }else
            {    
              f1[i]=f1[i-1];
              f2[i]=f2[i-1];
            }
        	}
        k[i]=(1LL*k[i-1]*(i%p))%p;
      }
    }
    int main()
    {
      scanf("%d%d",&t,&p);
     
      for(int i=1;i<=t;i++)
      {
    	  scanf("%d%d",&q[i][0],&q[i][1]);
        maxn=max(maxn,q[i][0]);
        maxm=max(maxm,q[i][1]);
      }
      work();
      for(int i=1;i<=t;i++)
    	{
    	  ans=((1LL*k[q[i][0]]%p)*1LL*(f1[q[i][1]]%p))%p;
        ans=(ans*1LL*(f2[q[i][1]]%p))%p;
        printf("%d
    ",ans);
      }
     
      return 0;
    }
    /*
    2 11
    6 3
    10 5
    
    */
    
  • 相关阅读:
    C语言移动一个点
    C语言数据结构无向图
    C语言学生管理系统(C语言课程设计/精简版)
    C语言贪吃蛇
    2017蓝桥杯九宫幻方(C++B组)
    2017蓝桥杯Excel地址(C++C组)
    2017蓝桥杯杨辉三角(C++C组)
    2017蓝桥杯算式900(C++C组)
    2017蓝桥杯兴趣小组(C++C组)
    javascript 的默认对象
  • 原文地址:https://www.cnblogs.com/yangyaojia/p/6434611.html
Copyright © 2020-2023  润新知