费马小定理题

费马小定理:假如p是质数,且gcd(a,p)=1,那么

a^{p-1}\equiv 1\left ( mod \ p \right )

A题HDU - 4704

首先是挡板法(隔板法),然后用\binom{n}{m}=\binom{n-1}{m}+\binom{n-1}{m-1}即可,高中数学范围不多叙述。

然后得到答案是2^{^{N-1}}

这题读入数据大10^{100000},就算快速幂也肯定TLE,所以用费马小定理,把数据规模降到int 范围内,时间复杂度降低

因为1e9+7是一个素数,(基本可以假设N-1不是1e9+7的倍数,这一点我没想到,所以没写出来。。。。)

所以可以(1e9+7)^N对(1e9+7-1)取余,以下是代码:

#include<iostream>
#include<string.h>
#define MOD 1000000007 
using namespace std;
const int N=1e7+1;
//const int MOD=1e9+7;
char s[N];
int maxx;
int main()
{
    while(scanf("%s",s)!=EOF)
    {
    int l=strlen(s);
    long long k=0;
    s[l-1]-=1;//计算N-1 
    for(int i=0;i<l;i++)
    {
        k=k*10+s[i]-'0';
        k=k%(MOD-1);//费马小定理 
    }
    //cout<<k<<endl;
    long long t=2;
    long long ans=1;
    while(k>0)
    {
        if(k%2==0)
        {
            
        }
        else
        {
            ans=ans*t%MOD;
        }
        k/=2;
        t=t*t%MOD;
    }
    cout<<ans<<endl;
    }
}

第二题:HDU - 1395

2^{x} \ mod\ n\equiv 1

这个题目暴力求出答案:每此取余数即可

如果是偶数,直接跳出,奇数一定成立(证明听说要用欧拉函数,笔者最近在看数论方面的东西,奇数证明部分留个坑。)

#include<iostream>
#include<math.h>
#define ll unsigned long long
using namespace std;
int main()
{
    ll n;
    while(cin>>n)
    {
        ll count=1;
        ll t=2;
        if(n%2==0||n<=1)
        {
            printf("2^? mod %d = 1\n",n);
        }
        else
        {
            while(true)
            {
                if(t%n==1)break;
                count++;//计数 
                t=t*2%n; 
            }
            printf("2^%d mod %d = 1\n",count,n);
        }
    }
}

第三题:HDU - 5750

这题关键是素数筛

在素数筛里面最快的就是O(N)的复杂度

用素数和题目中给的d相乘,可以得到一些n的含有d因子的数,然后选择合适的跳出条件(其实观察题目也可以发现,在许多情况下,非常容易跳出,因为样例中有好几个是0)

(以后不管什么题都用long long)

然后又被cin比scanf()慢坑了,改scanf

上代码(有注释):
#include<iostream>
#include<string.h>
#define ll long long
using namespace std;
const int N=1e5+5;
bool vis[N];
ll prime[N];
ll pri(int n){
    memset(vis,1,sizeof(vis));
    ll num=0;
    for(ll i=2;i<=n;i++)
    {
        if(vis[i])prime[++num]=i;
        for(int j=1;j<=num&&i*prime[j]<=n;j++)
        {
            vis[i*prime[j]]=0;
            if(i%prime[j]==0)break;
        }
    }
    return num;
}
int main()
{
    int t;
    cin>>t;
    int cnt=pri(N-1);
    while(t--)
    {
        ll ans=0,n,d;
        scanf("%lld%lld",&n,&d);//scanf读入 比cin快 用cin会TLE 
        for(int i=1;i<=cnt;++i)
        {
            if(prime[i]<=d&&prime[i]*d<n)ans++;//在范围内 
            if(prime[i]>d||prime[i]*d>=n)break;//超过范围 
            if(d!=prime[i]&&d%prime[i]==0)break;//枚举了d的因数跳出 
        }
        cout<<ans<<endl;
    }
}

https://cn.vjudge.net/contest/273543#problem/A

猜你喜欢

转载自blog.csdn.net/baidu_39394563/article/details/84799040