luogu P4752

给定一个数字 A ,这个 A 由 a1,a2,...,aN 相乘得到。

给定一个数字 B ,这个 B 由 b1,b2,,bM 相乘得到。

如果 A/B 是一个质数,请输出YES,否则输出NO

输入输出格式

输入格式:

 

每个测试点包含多组数据,第一行读入一个整数 TT 表示数据组数,对于每组数据:

第一行输入两个整数 N,M ,分别表示 A 由 N 个数字相乘得到, B 由 M 个数字相乘得到。

第二行输入 N 个整数,分别表示组成 A 的 N 个数字。

第三行输入 M 个整数,分别表示组成 B 的 M 个数字。

保证对于一个数字,其在 {bi}中出现的次数不多于在 {ai} 中出现的次数。

 

输出格式:

 

对于每组数据:

如果 A/B 是一个质数,请输出YES,否则输出NO

在输出 YES 或 NO后输出一个换行符。

 

输入输出样例

输入样例#1: 
2
3 2
5 7 7
5 7
4 2
5 7 7 7
5 7
输出样例#1: 
YES
NO

说明

1N100000

0MN

1ai,bi1012

1T10

N100000

 

 吐槽两句:

说好的难度从普及-到省选呢?普及-难度呢?最低的只有 普及+提高-的吧,然而我看着都想省选题。

体面解读解题分析:

题面简洁易懂,只是根据数据范围,貌似如果相乘的话long long 恐怕都盛不开。

然而细细读题目你会发现,有句很重要的话(红色标注)

既然是A/B,那么 集合A 与 集合B中的元素可以先提前约分啊。

这句话说的数字在 B 中出现次数一定少于 A中的次数,那么这说明B中的数字可以在A中全部约去,那么B=1咯,所以A/B的值不就是A中所剩元素的乘积嘛。

少年,莫着急,等我把话说完。

A中元素的乘积难道就会小?绝对有数据会乘不开。

所以在约分完以后,需要一个比较有意思的判断。

你想A中元素的乘积,既然可以乘出来,那么一定就不是素数(prime).(emmm...说的在理)

还需要加一个判断,如果A中只剩下一个元素后,那么乘积就是这个数了,则需要判断一下这个数是否为素数。

1012大的数,用什么判断呢?

当然是 Miller_Rabin 算法判断了,下面给出了模板。

所以此题就解决完了。

 

Miller_Rabin模板

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

ll add_mod(ll a,ll b,ll mod){    //快乘法 基于快速幂的二分思想 
    ll ans=0;                    //由于考虑到取模数很大 快速幂会溢出 
    while(b){                    //必须使用该方法 
        if(b&1)                    //我这里写的是非递归版 
            ans=(ans+a)%mod;
        a=a*2%mod;
        b>>=1;
    }
    return ans;
}

ll pow_mod(ll a,ll n,ll mod){            //快速幂 递归版 
    if(n>1){                            
        ll tmp=pow_mod(a,n>>1,mod)%mod;
        tmp=add_mod(tmp,tmp,mod);
        if(n&1) tmp=add_mod(tmp,a,mod);
        return tmp;
    }
    return a;
}

bool Miller_Rabbin(ll n,ll a){//米勒拉宾素数判断函数主体
    ll d=n-1,s=0,i;    
    while(!(d&1)){            // 先把(2^s)*d 算出来 
        d>>=1;
        s++;
    }
    ll t=pow_mod(a,d,n);    //a^d取一次余判断 
    if(t==1 || t==-1)        //一或负一则可以声明这可能是质数 
        return 1;
    for(i=0;i<s;i++){                //不是的话继续乘上s个2 
        if(t==n-1)            //(n-1)*(n-1)%n=1 这一步是优化 
            return 1;
        t=add_mod(t,t,n);    // 快乘 
    }
    return 0;
}

bool is_prime(ll n){
    ll i,tab[4]={3,4,7,11};//本来应该取[1,n]内任意整数 
    for(i=0;i<4;i++){                //但一般这几个数足以,不需要太多组测试 
        if(n==tab[i])
            return 1;        //小判断小优化~ 
        if(!n%tab[i])
            return 0;
        if(n>tab[i] && !Miller_Rabbin(n,tab[i]))
            return 0;
    }
    return 1;
}
    
int main(){
    ll n;
    scanf("%lld",&n);
    if(n<2) printf("No");
    else if(n==2) printf("Yes");
    else{
        if(!n%2) printf("No");
        else if(is_prime(n))
            printf("Yes");
        else printf("No");
    }
    return 0;
}

 

此题AC代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <map>
using  namespace std;
#define N int(1e6+2)
#define M int(2e5+2)
#define ll long long
ll n,m,T;
ll a[N],b,c[N],tot;
map<ll,int> f;
bool vis[N];
ll sum;
ll add_mod(ll a,ll b,ll mod)
{
    ll ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        a=a*2%mod;
        b>>=1;
    }
    return ans;
}

ll pow_mod(ll a,ll n,ll mod)
{
    if(n>1)
    {
        ll tmp=pow_mod(a,n>>1,mod)%mod;
        tmp=add_mod(tmp,tmp,mod);
        if(n&1) tmp=add_mod(tmp,a,mod);
        return tmp;
    }
    return a;
}

bool Miller_Rabbin(ll n,ll a)
{
    ll d=n-1,s=0,i;
    while(!(d&1))
    {
        d>>=1;
        s++;
    }
    ll t=pow_mod(a,d,n);
    if(t==1 || t==-1)
        return 1;
    for(i=0; i<s; i++)
    {
        if(t==n-1)
            return 1;
        t=add_mod(t,t,n);
    }
    return 0;
}
bool is_prime(ll n)
{
    ll i,tab[4]= {3,4,7,11};
    for(i=0; i<4; i++)
    {
        if(n==tab[i])
            return 1;
        if(!n%tab[i])
            return 0;
        if(n>tab[i] && !Miller_Rabbin(n,tab[i]))
            return 0;
    }
    return 1;
}
int main()
{

    scanf("%lld",&T);
    while(T--)
    {
        sum=1;
        ll k=0,p;
        scanf("%lld%lld",&n,&m);
        for(int i=1; i<=n; i++)scanf("%lld",&a[i]),f[a[i]]++;;
        for(int i=1; i<=m; i++)scanf("%lld",&b),f[b]--;
        for(int i=1; i<=n; i++)
        {
            if(f[a[i]])k+=f[a[i]],f[a[i]]=0,p=a[i];
        }
        f.clear();
        if(k==1)
        {
            n=p;
            if(n<2) printf("NO\n");
            else if(n==2) printf("YES\n");
            else
            {
                if(!n%2) printf("NO\n");
                else if(is_prime(n))
                    printf("YES\n");
                else printf("NO\n");
            }
        }
        else printf("NO\n");
    }
}

 总的来说这题不是特别难,思想比较好。

posted @ 2018-07-15 08:06  Manjusaka丶梦寒  阅读(274)  评论(0编辑  收藏  举报