2020牛客暑期多校训练营(第四场)解题报告 BFH

题目链接:https://ac.nowcoder.com/acm/contest/5669

 B-Basic Gcd Problem

题意:给你一个函数f_{c}(x)的定义,求解f_{c}(n)%10^9+7

输入:

2
3 3
10 5

输出:

3
25

hint:规律

通过举例几个数就可以发现其实他就是在求 c^{cnt} ,其中cnt表示n的质因子幂次之和,比如 18=2^1*3^2 ,那么cnt=1+2=3,那么f_{c}(18)=c^3。由于输入量有点大,需要提前预处理一下这个cnt,这边采用的是dp处理。还有一点就是需要特判一下n=1的情况cnt=0,所以输出1。

#include<bits/stdc++.h>
#define PB push_back
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define FI first
#define SE second
#define mem(a) memset(a,0,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const double pi=acos(-1),eps=1e-8;
const int maxn = 1e6+5;
const int mod = 1e9+7;
LL POW(LL a,LL b,LL p){
	LL ans=1;
	while(b){
		if(b&1)ans=ans*a%p;
		a=a*a%p;
		b>>=1; 
	}
	return ans;
}
int main(){
	vector<int>dp(maxn+1,1);
	for(int i=2;i<maxn;i++){
		for(int j=2;1LL*i*j<=1e6;j++){
			dp[i*j]=max(dp[i*j],dp[i]+dp[j]);
		}
	}
	int t;scanf("%d",&t);
	while(t--){
		int n,c;scanf("%d%d",&n,&c);
		if(n==1)printf("1\n");
		else printf("%lld\n",POW(c,dp[n],mod));
	}
	return 0;
}

 F-Finding the Order

题意:给你两条线和线上的四个点ABCD,其中AB在上面一条线 ,CD在下面一条线,给定AC,AD,BC,BD大小,A在B左边,问你四个点的先后顺序。

 输入:

2
3 5 5 3
5 3 3 5

输出:

AB//CD
AB//DC

hint:

  • 在CD这条线上找一点设为E,f=AE+BE,过AB做中垂线交CD于F,此时f最小,然后离F点越远,f值越大。

  • 当CD位于F点左侧时,只需要判断f_cf_d大小即可,前者大的话说明顺序是CD,否则是DC

  • 当CD位于F点右侧时,同理,前者大说明顺序是DC,否则是CD

  • 当CD位于F点两侧时,只需判断AC和BC大小以及AD和BD大小,那D举例子,如果说AD小于BD,那么就说明D在F左边,否则在右边,这就间接得出了CD的左右关系

#include<bits/stdc++.h>
#define PB push_back
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define FI first
#define SE second
#define mem(a) memset(a,0,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const double pi=acos(-1),eps=1e-8;
const int maxn = 1e6+5;
const int mod = 1e9+7;
int main(){
	int t;scanf("%d",&t);
	while(t--){
		int a,b,c,d;
		scanf("%d%d%d%d",&a,&b,&c,&d);
		int lc,rc,ld,rd;//cd相对f方向
		if(a<b)lc=1,rc=0;
		else lc=0,rc=1;
		if(c<d)ld=1,rd=0;
		else ld=0,rd=1;
		if(lc&&ld){//都在左侧
			if(a+b<c+d)puts("AB//DC");
			else puts("AB//CD");
		}else if(rc&&rd){//都在右侧
			if(a+b<c+d)puts("AB//CD");
			else puts("AB//DC");
		}else{//在两侧
			if(a<b)puts("AB//CD");
			else puts("AB//DC"); 
		}
	}
	return 0;
}

 H-Harder Gcd Problem

题意:给你1-n个数,让你取m对互不相同的数,且不放回,使得每对的两个数不互质,求m的最大值,并输出m对。

输入:

2
4
10

 输出:

1
2 4
4
3 9
5 10
8 2
4 6

hint:筛法+贪心

贪心策略:倒序查找质数,再以它为基准往上筛,因为大质数能配对的数相对小质数较少,要优先配对大的质数。当筛完的个数是奇数时,可以考虑把其中的一个偶数挑出来,存放在even数组里,最后在even数组中随机配对。

#include<bits/stdc++.h>
#define PB push_back
#define PII pair<int,int>
#define PLL pair<long long,long long>
#define FI first
#define SE second
#define mem(a) memset(a,0,sizeof(a))
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const double pi=acos(-1),eps=1e-8;
const int maxn = 2e5+5;
const int mod = 1e9+7;
bool isprime[maxn],vis[maxn];
int prime[maxn],primesize;
void get_prime(int size){//欧拉筛素数 
	memset(isprime,true,sizeof(isprime));
	isprime[1]=false;
	for(int i=2;i<=size;i++){
		if(isprime[i])prime[primesize++]=i;
		for(int j=0;j<primesize&&i*prime[j]<=size;j++){
			isprime[i*prime[j]]=false;
			if(i%prime[j]==0)break;
		}
	}
}
int cnt,n;
pair<int,int>p[maxn];
vector<int>even;
void make(int l,int r){//配对 
	p[cnt].first=l;
	p[cnt++].second=r;
}
void create(vector<int>&v){//数组随机配对 
	int len=v.size();
	for(int i=0;i<len;i+=2){
		if(i+1==len)break;
		make(v[i],v[i+1]);
	}
}
void f(int x){//素数筛取 
	vector<int>v;
	for(int i=x;i<=n;i+=x){
		if(!vis[i]){
			v.push_back(i);
			vis[i]=true;
		}
	}
	int len=v.size();
	if(len==1)return;
	if(len&1){
		for(auto it=v.begin();it!=v.end();it++){
			if(*it%2==0){//挑出一个偶数
				even.push_back(*it);
				v.erase(it);
				break;
			}
		}
	}
	create(v);
}
void print(){//输出结果 
	printf("%d\n",cnt);
	for(int i=0;i<cnt;i++){
		printf("%d %d\n",p[i].first,p[i].second);
	}
}
int main(){
	get_prime(maxn);
	int t;scanf("%d",&t);
	while(t--){
		memset(vis,false,sizeof(vis));
		even.clear();
		scanf("%d",&n);cnt=0;
		for(int i=n;i>1;i--){
			if(isprime[i]){
				f(i);
			}
		}
		create(even);
		print();
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43911947/article/details/107480915