3356. 解方程

单点时限: 2.0 sec

内存限制: 256 MB

简而言之,本题任务就是解方程。共有两个子任务。

子任务 1:小学生
作为小学生,我们只会解一元一次方程,一元一次方程最终都可以化为 ax=n 的形式。现在问:对于给定的 n,要使得 x 有正整数解,总共可以取多少个不同的 a 呢?

子任务 2:中学生
作为中学生,我们只会解二元一次不定方程,二元一次不定方程最终都可以化为 ax+by=n 的形式。现在问:对于给定的 n,要使得 x,y 有正整数解,总共可以取多少对不同的 (a,b) 呢?

输入格式
输出一行两个整数 q,n (q∈{1,2})。

q=1 表示你现在要解决小学生的情况,q=2 表示你现在要解决中学生的情况。

数据规模约定(每个测试点占本题总分值的 10%):

测试点 q n
1 =1 1≤n≤1 000
2, 3 =1 1≤n≤300 000
4, 5 =2 1≤n≤50
6, 7 =2 1≤n≤500
8, 9 =2 1≤n≤50 000
10 =2 1≤n≤300 000
输出格式
输出一个整数,表示答案。

样例
input
2 4
output
6
input
1 10
output
4
提示
当 q=1,n=10 时,a 可以取 1,2,5,10。

当 q=2,n=4 时,(a,b) 可以取 (1,1),(1,2),(1,3),(2,1),(2,2),(3,1)。
****方法一:
扩展欧几里得算法得:ax+by=n有解的充要条件为:
n%gcd(a,b)==0
可一个一个枚举,在验证x,y是否为整数。此方法超时了。

方法二:
枚举n-ax=t,t=by。枚举t的公约数b。此时(a,b)为解,用visit[b]=a表示计算过了

//方法一
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int f(int n) {
	int ans=2;
	for(int i = 2; i<=n/2; i++) {
		if(n%i==0)
			ans++;
	}
	return ans;
}
bool text(int n,int a,int b) {
	for(int i = 1; i*b < n; i++)
		if((n-i*b) % a == 0)
			return true;
	return false;
}
int count(int n) {
	int ans=0;
	for(int i = 1; i < n; i++) {
		for(int j=1; j <=n-i; j++) {
			if(n%__gcd(i,j)==0&&text(n,i,j)) {
				ans++;
			}
		}
	}
	return ans;
}
int main() {
	int q,n;
	cin>>q>>n;
	if(q==1) {
		cout<<f(n)<<endl;
	} else {
		cout<<count(n)<<endl;
	}
	return 0;
}

//方法二:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int q,n;
int a,b;
vector<int> num[300005];
int visit[300005];
int main() {
	scanf("%d %d",&q,&n);
	if(q==1) {
		int ant=0;
		for(int i=1; i<=n; i++) {
			if(n%i==0) {
				ant++;
			}
		}
		printf("%d\n",ant);
	} else {
		int ans=0;
		for(int i=1; i<n; i++) {
			num[i].clear();
			for(int j=1; j*j<=i; j++) {
				if(i%j==0) {
					num[i].push_back(j);
					if(j*j!=i)
						num[i].push_back(i/j);
				}
			}
		}
		memset(visit,0,sizeof(visit));
		for(int a=1; a < n; a++) {
			for(int x=1; a*x < n; x++) {
				int t=n-a*x;
				for(int i = 0; i < num[t].size(); i++) {
					if(visit[num[t][i]]!=a) {
						ans++;
						visit[num[t][i]]=a;
					}
				}
			}
		}
		printf("%d\n",ans);
	}
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值