Simple

【问题描述】
对于给定正整数 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
",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
",q);
        else if (n>q&&m<=q) printf("%lld
",q-q/m);
        else doit();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wutongtong3117/p/7673470.html