单点时限: 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
#include
#include
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
#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;
}