luogu 7月月赛 #A P4752 Divided Prime
Posted rmy020718
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu 7月月赛 #A P4752 Divided Prime相关的知识,希望对你有一定的参考价值。
给定一个数字 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≤N≤100000
0≤M≤N
1≤ai?,bi?≤1012
1≤T≤10
∑N≤100000
吐槽两句:
说好的难度从普及-到省选呢?普及-难度呢?最低的只有 普及+提高-的吧,然而我看着都想省选题。
体面解读解题分析:
题面简洁易懂,只是根据数据范围,貌似如果相乘的话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 "); else if(n==2) printf("YES "); else { if(!n%2) printf("NO "); else if(is_prime(n)) printf("YES "); else printf("NO "); } } else printf("NO "); } }
总的来说这题不是特别难,思想比较好。
以上是关于luogu 7月月赛 #A P4752 Divided Prime的主要内容,如果未能解决你的问题,请参考以下文章