【问题描述】
对于给定正整数 n,m,我们称正整数c为好的,当且仅当存在非
负整数x,y,使得 n*x+m*y=c。
现在给出多组数据,对于每组数据,给定 n,m,q,求[1,q]内有
多少个正整数不是好的。
【输入格式】
第一行,一个整数T表示数据组数。
接下来每行三个数,分别表示 n,m,q,即一组询问。
【输出格式】
对于每组数据,输出一行表示答案。
【样例输入】
2
78 100 4
70 3 34
【样例输出】
4
23
【数据范围及约定】
对于30%的数据,n,m,q≤100。
对于60%的数据,n,m,q≤10^5。
对于100%的数据,n≤10^5,m≤10^9,q≤10^18,T≤10。
分析:
t1
还没睡醒,打了一个暴力就跑了
之后找了一个AC程序(没错,是yhzq的,%%%)
一点一点摸索ta的思路
题目可以看为是计算 n*x+y*m=c 中c的个数
两个参数,不大好搞,咋办。。。
设:n > m (之后的所有计算都是基于这个条件的)
我们把n用m表示,
n=k*m+t
因为m<=100000, 所以t<100000
我们开一个t数组,t[x]记录
n的倍数中%m==x的最小数
x的取值最多只有100000种,
换句话说就是总有循环的一天
好了,现在我们有了这个t数组
要怎么计算答案呢
首先,有一个显然的结论,
如果从c符合条件,那么c的倍数都符合条件
那我们只要找到最小的满足条件且不同的c,
ans+=(q/c)
很好,问题又简化一步
这个t数组算出来不是用来看的啊,我们要好好利用
假设我们有一个t[i]!=0
我们要保证c中有n,
(也可以没有,这时候i==0,也适用于以下的算法)
c就要减去t[i] ,
(t[i]是n的倍数中%m==i的最小值,可以视为是一种与其他的都互斥的情况)
这样c中就一定包含n(的倍数)了,
剩下的值就可以让m随意分配了,
文字不明白,直接看式子:
ans+=(q-t[i])/m+1;
tip
诶??? 这个1是从哪来的???
answer:q-t[i]中没有m也是一种方案啊
(换句话说就是,n*x+y*m=c中y=0)
最后输出的时候:
printf(“%lld”,q-ans+1);
诶??? 这个+1又是什么???
answer:在t[i],i==0的时候我们的ans多加了一个1
因为c的取值是[1,q],也就是说 n*x+y*m=c => x,y不同为0
注意
q-t[i]>=0不要忘了判断
这里写代码片
#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
ll n,m,q;
ll t[100010];
void swp(ll &a,ll &b){ll r=a;a=b;b=r;return;}
void doit()
{
int i;
memset(t,-1,sizeof(t)); //余数
for (i=0;;i++)
{
ll sum=n*i;
if (t[sum%m]!=-1) //循环了
break;
t[sum%m]=sum; //%m==当前余数的最小n的倍数
}
ll ans=0;
for (i=0;i<m;i++) //t的取值:0~m-1
if (t[i]!=-1&&(q-t[i]>=0))
ans+=(q-t[i])/m+1;
printf("%lld\n",q-ans+1);
}
int main()
{
int T;
//freopen("simple.in","r",stdin);
//freopen("simple.out","w",stdout);
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld%lld",&n,&m,&q);
if (n<m) swp(n,m); //n>m
if (n>q&&m>q) printf("%lld\n",q);
else if (n>q&&m<=q) printf("%lld\n",q-q/m);
else doit();
}
return 0;
}