Acwing蓝桥杯省赛专题训练之数论(相关真题和模板题)

题目:1246. 等差数列

在这里插入图片描述
题解:数论+最大公约数。

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=1e5+10;
int n;
int a[N];
int gcd(int x,int y){
	return y?gcd(y,x%y):x;
}
int main() {
	cin>>n;
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	sort(a+1,a+1+n);
	int res=0;
	for(int i=2;i<=n;i++){
		res=gcd(res,a[i]-a[1]);
	}
	if(res!=0)
		cout<<(a[n]-a[1])/res+1;
	else 
		cout<<n;
	return 0;
}

题目:1295. X的因子链

在这里插入图片描述
题解:分解质因数+组合计数

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int min_pri[N];
int pri[N],k=0;
bool sta[N];
void get_primes(int u){
	for(int i=2;i<=u;i++){
		if(!sta[i]){
			min_pri[i]=i;
			pri[k++]=i;
		}
		for(int j=0;pri[j]<=u/i;j++){
			int t=pri[j]*i;
			sta[t]=1;
			min_pri[t]=pri[j];
			if(i%pri[j]==0) break;
		}
	}
}
int main() {
	get_primes(1<<20);
	int x;
	while(scanf("%d",&x)!=EOF){
		int ct[N];
		int cnt[N];
		int idx=0;
		int sum=0;
		while(x>1){
			int t=min_pri[x];
			ct[idx]=t;
			cnt[idx]=0;
			while(x%t==0&&x>1){
				cnt[idx]++;
				sum++;
				x/=t;
			}
			idx++;
		}
		LL ans=1;
		for(int i=1;i<=sum;i++){
			ans*=i;
		}
		for(int i=0;i<idx;i++){
			for(int j=1;j<=cnt[i];j++){
				ans/=j;
			}
		}
		printf("%d %lld\n",sum,ans);
	}
	return 0;
}

题目:1299. 五指山

在这里插入图片描述
题解:扩展gcd,线性同余方程模板题

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;

LL exgcd(LL a,LL b,LL &x,LL &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	LL t=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return t;
}
int main() {
	LL t;
	LL n,d,x,y,a,b;//没事就用LL ,避免越界
	cin>>t;
	while(t--){
		scanf("%d%d%d%d",&n,&d,&x,&y);
		LL res=exgcd(d,n,a,b);
		if((y-x)%res!=0){
			printf("Impossible\n");
		}else{
			a*=(y-x)/res;
			n/=res;
			printf("%lld\n",(a%n+n)%n);
		}
	}
	return 0;
}

题目:1223. 最大比例

在这里插入图片描述
在这里插入图片描述
题解:数论+最大公约数+辗转相除法。先用最大公约数求出每一项和第一项的比值,然后再用辗转相除法求出比值中最大的公约数

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
LL a[110];
LL gcd(LL x, LL y){
	return y?gcd(y,x%y):x;
}
LL gcd_sub(LL x,LL y){
	if(x<y) swap(x,y);
	if(y==1) return x;
	return gcd_sub(y,x/y);
} 

int main() {
	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%lld",&a[i]);
	}
	sort(a,a+n);
	LL b[110],c[110];
	int k=0;
	for(int i=1;i<n;i++){
		if(a[i]!=a[i-1]){
			LL t=gcd(a[0],a[i]);
			b[k]=a[i]/t;
			c[k]=a[0]/t;
			k++;
		}
	}
	LL up=b[0],down=c[0];
	for(int i=1;i<k;i++){
		up=gcd_sub(up,b[i]);
		down=gcd_sub(down,c[i]);
	}
	printf("%lld/%lld",up,down);
	return 0;
}

题目:1301. C 循环

在这里插入图片描述
题解:线性同余方程+扩展gcd

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;

LL exgcd(LL a,LL b,LL &x,LL &y){
	if(b==0){
		x=1,y=0;
		return a;
	}
	LL t=exgcd(b,a%b,y,x);
	y-=a/b*x;
	return t;
}
int main() {
	LL a,b,c,k;
	while(scanf("%lld%lld%lld%lld",&a,&b,&c,&k)!=EOF){
		if(a==0&&b==0&&c==0&&k==0) break;
		LL x,y;
		LL n=(1ll<<k);//这里一定要用LL型的1,不然过不了
		LL t=exgcd(c,n,x,y);
		if(abs(b-a)%t!=0){
			puts("FOREVER");
		}else{
			x*=(b-a)/t;
			n/=t;
			printf("%lld\n",(x%n+n)%n);
		}
	}
	return 0;
}

题目:1225. 正则问题

在这里插入图片描述
题解:递归+字符串处理

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
char a[110];
int k=0,len;
int dfs(){
	int res=0;
	while(k<len){
		if(a[k]=='('){
			k++;
			res+=dfs();
			k++; //记住,只有跳出)才能k++:
		}else if(a[k]=='|'){
			k++;
			res=max(res,dfs());
		}else if(a[k]==')'){
			//k++;这里不能 k++,只有遇见(的那边才能,因为有|的存在
			return res;
		}else{
			res++;
			k++;
		}
	}
	return res;
}
int main() {
	scanf("%s",a);
	len=strlen(a);
	cout<<dfs();
	return 0;
}

题目:1243. 糖果

在这里插入图片描述
题解:dp+状态压缩

#include <bits/stdc++.h> 
using namespace std;
typedef long long LL;
typedef pair<int ,int >PII;
const int N=(1<<20)+10;
int n,m,k; 
int a[110];
int dp[N];
int main() {
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1;i<=n;i++){
		int x;
		for(int j=1;j<=k;j++){
			scanf("%d",&x);
			x--;
			a[i]|=1<<x;
		}
		//cout<<a[i]<<endl;
	}
	memset(dp,-1,sizeof dp);
	dp[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=0;j<(1<<m);j++){
			if(dp[j]==-1) continue;
			int t=j|a[i];
			if(dp[t]==-1||dp[t]>dp[j]+1){
				dp[t]=dp[j]+1;
			}
		}
	}
	cout<<dp[(1<<m)-1];
	return 0;
}
  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值