您的位置:首页 > 其它

[UVa 11440]Help Tomisu 数论 欧拉函数+拓欧逆元

2014-08-04 21:09 435 查看
Problem D

Help Mr. Tomisu

Input:
Standard Input
Output: Standard Output


After wasting a significant time of his life in problem-setting, Mr. Tomisu is now searching for glory: A glory that will make him famous likeGoldbach and rich like Bill Gates :). And he has chosen the field of Number Theory as his prime interest. His
creator did not make him very bright and so he needs your help to solve an elementary problem, using which he will begin his pursuit for glory!



Tomisu has come to know that finding out numbers having large prime factors are very important in cryptography. Given two integers N and M,he aims to count the number of integers x between 2 and N! (factorial N), having
the property that all prime factors of x are greater than M.



Input
The input file contains at most 500 lines of inputs. Each line contains two integers N (1<N<10000001) and M (1≤M≤N and N-M≤100000). Input is terminated by a line containing two zeroes. This line should not be processed.



Output

For each line of input produce one line of output. This line contains the value T % 100000007 (Modulo 100000007 value of T). Here T is the total number of numbers between 1 and N! (factorial N) which have prime factors greater than M.



100 10

100 20

10000 9000

0 0

43274465

70342844

39714141

Problemsetter: Shahriar Manzoor

Special Thanks: Per Austrin



题目大意

求在1~N!之中,其所有质因数都大于M的数字个数。

解题思路

刚开始想到用容斥原理,处理数字中有偶数个不符合要求的质因数个数的,减去奇数个不符合要求质因数个数的。

对于每一个质因数都处理一下

TLE……

最后发现

N (1<N<10000001) and M (1≤M≤N and N-M≤100000).

500组数据,之前线性的处理方法也会直接挂

处理样例的数据发现答案是

(100!*48/210-1)mod 100000007

210 和 48 间的关系就是欧拉函数了……

换种思路,就是不超过M的所有质数的乘积P,所有数字种与P互质的个数,便是欧拉函数的典型应用了。(若不互质就拥有的小于等于M的质因数)

于是我们可以处理前k个质数的乘积,算出他们的欧拉函数(每个质数减一之积)。
就可以直接愉快的使用逆元了。
PS:由于UVa不限内存……可以直接把一些数据放在内存里咯,运行更快一些。
TLE的容斥代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>

#define sqr(x) ((x)*(x))
#define LL long long 
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define eps 1e-10
#define mod 100000007ll
using namespace std;
int co[100005];
LL pri[100005],pn;
void egcd(LL a,LL b,LL &x,LL &y)
{
    if (b==0)
    {
        x=1,y=0;
        return ;
    }
    egcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-a/b*y;
}
int main()
{
    LL n,m;
    pn=0;
    for (int i=2;i<=100000;i++)
    {
        if (co[i]==0) {
        pri[++pn]=i;
        for (int j=2*i;j<=100000;j+=i)
            co[j]=1;
        }
    }
    while (~scanf("%lld%lld",&n,&m),n+m)
    {
        LL t=1;
        for (LL i=1;i<=n;i++)
            t=t*i%mod;
        LL preodd=0;
        LL preeven=t;
        LL ansodd,anseven;
        for (LL i=1;pri[i]<=m;i++)
        {
            LL x,y,di;
            egcd(pri[i],mod,x,y);
            // printf("%lld %lld \n", pri[i],i);
            di=(x+mod)%mod;
            ansodd=(preeven*di)%mod;//枚举之前的奇偶
            anseven=(preodd*di)%mod;
            ansodd=(ansodd+preodd)%mod;
            anseven=(anseven+preeven)%mod;
            // printf("%lld \n", ansodd);
            // printf("%lld \n", anseven);
            preeven=anseven;//保存下来
            preodd=ansodd;
            
        }
        LL ans=(-ansodd+anseven+mod-1)%mod;
        printf("%lld\n",ans);
    }
    return 0;
}


AC代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>

#define sqr(x) ((x)*(x))
#define LL long long 
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define eps 1e-10
#define mod 100000007ll
using namespace std;
int co[10000115];
LL pri[10000115],pn;
LL fac[10000115];
LL ff[1000115];
LL fm[1000115];
void egcd(LL a,LL b,LL &x,LL &y)
{
    if (b==0)
    {
        x=1,y=0;
        return ;
    }
    egcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-a/b*y;
}
int main()
{
    LL n,m;
    pn=0;
    for (int i=2;i<=10000107;i++)
    {
        if (co[i]==0) 
            pri[++pn]=i;
        for (int j=1;(i*pri[j]<=10000107)&&(j<=pn);j++)
        {
            co[i*pri[j]]=1;
            if (i%pri[j]==0) break;
        }
    }
    fac[1]=1;
    for (LL i=2;i<=10000107;i++)
        fac[i]=(fac[i-1]*i)%mod;
    ff[0]=1;
    fm[0]=1;
    for (int i=1;i<=pn;i++){
        fm[i]=(fm[i-1]*pri[i])%mod;
        ff[i]=(ff[i-1]*(pri[i]-1))%mod;}//fm[i]表示前i个质数的乘积,ff[i]表示对应的欧拉函数
    while (~scanf("%lld%lld",&n,&m),n+m)
    {
        LL t=fac
;
        LL pt=upper_bound(pri+1,pri+pn+1,m)-pri;
        if (pri[pt]>=m) pt--;
        t=t*ff[pt]%mod;
        LL x,y;
        egcd(fm[pt],mod,x,y);
        x=(x+mod)%mod;
        t=(t*x-1+mod)%mod;
        printf("%lld\n",t);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: