• 联赛膜你测试20 T1 Simple 题解 && NOIP2017 小凯的疑惑 题解(赛瓦维斯特定理)


    前言:

    数学题,对于我这种菜B还是需要多磨啊

    Simple

    首先它问不是好数的数量,可以转化为用总数量减去是好数的数量。
    求“好数”的数量:
    由裴蜀定理得,如果某个数(i)不能整除(gcd(n,m)),那么一定不是好数。
    所以,我们把(n,m,q)分别除以(gcd(n,m)),是不影响得出的“好数”数量的。
    好,那么现在(n,m)就互质了。
    现在,就把问题转化为了(用比较形象化的语言来说,就是)有(n,m)互质,求([1,q])中有多少个数能被若干个(n,m)相加之后拼起来。
    这个东西简单枚举两维的话,复杂度显然无法接受。我们可以考虑只枚举一维。
    (n)的系数是(x)(m)的系数是(y),且(n)小于(m)
    (n*x+m*y=c);
    那么就可以枚举(y),求(x)的数量即可。
    边界问题很重要。
    我们考虑y的边界,因为要算((c-m*y)/n),所以(m*y<=c);
    然后会发现一个问题,如下图。

    上面的长线段代表某个能被拼成的数,我们可以发现,如果枚举(m)的个数等于(4)时,这个数会被计算到。枚举(m)的个数等于(0),即(n)的个数等于(5)时,这个数又会被计算到,就会算重。
    那么怎么去重呢?
    我们会发现,因为(n,m)互质,上面的情况发生且只会发生在枚举的(y)大于等于(n)时才会出现。
    所以就有了y的第二个边界,(y<n);
    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    ll n,m,q;
    ll gcd(ll x,ll y){
    	return y==0 ? x : gcd(y,x%y) ;
    }
    void Solve(){
    	int T;scanf("%d",&T);
    	while(T--){
    		scanf("%lld%lld%lld",&n,&m,&q);
    		ll ans=q;
    		if(n>m) swap(n,m);
    		ll ss=gcd(n,m);
    		n/=ss;
    		m/=ss;
    		q/=ss;
    		for(register int i=0;i*m<=q&&i<n;++i) ans-=(q-1ll*i*m)/n+1;
    		printf("%lld
    ",ans+1);//ans+1的原因?
    	}
    }
    int main(){
    	freopen("simple.in","r",stdin);
    	freopen("simple.out","w",stdout);
    	Solve();
    	return 0;
    }
    
    

    这里还要注意一个点,最后(ans)要加一,原因是(x=0,y=0)的情况,这是不在([1,q])区间中的,相当于多减去一个,然后就要加回来。

    2.luogu P3951 小凯的疑惑 / [蓝桥杯2013省]买不到的数目

    链接

    这个题放在D1T1是来恶心人的吗。。。找到规律就秒切,找不到规律就心态炸裂?
    希望今年别出这种题。
    某工具人学长 所言,这玩意叫赛瓦维斯特定理。
    emmm。。。动动的证明看懂了一部分
    后来又看了这个链接疑似挂掉的博客
    发现竟然折磨简单。
    然后。。。我自己写的证明就先咕了吧

  • 相关阅读:
    创业公司新品如何寻求科技媒体的报道?
    DevStore分享:详析消费者十大心理学
    DevStore教你如何玩转饥饿营销?
    iClap分享:如何优雅的在 APP 中实现测试?
    java内部类
    Tostring 的用法
    Java 集合详解
    Java集合浅析
    异常--解析
    is-a 、have-a、和 like-a的区别
  • 原文地址:https://www.cnblogs.com/wwcdcpyscc/p/13853705.html
Copyright © 2020-2023  润新知