jzxx. 3130  我爱华杯赛

 

jzxx. 3130  我爱华杯赛

第22届华杯赛结束啦!还记得这道题吗?从自然数 1 至 2017 中选出一个数 n , 使得余下的 2016 个数的和除以 2003 的余 数与 n 除以 2003 的余数相同,则n=__________。今天把这题改编一下。(jzxx. 3130, code[vs]. 5848 )

    把2017改为n,2003改为k,如果选择的数字t除以k的余数等于除t以外的其他数字的数字和除以k的余数相同则输出所有解t。如果此题无解,输出"Can't find the number!".

输入

一行,n和k。(n<=20000000;0<k<=n)(有1到n个数,k为除数)

输出

t的所有解,一行一个或“Can't find the number!”

样例输入

2017 2003

样例输出

1054

来源

http://oj.jzxx.net/problem.php?id=3130

【思路1】直接枚举i∈ [1~n],只要i%k==(sum-i)%k即出解。此法因是暴力枚举作取余运算,耗时较长,接近1秒的限时。

#include <cstdio>
int main()
{
    long long n, i, k, t, sum, f = 1;
    scanf("%lld%lld", &n, &k);
    sum = n * (n + 1) / 2;
    for (i = 1; i <= n; i++)
        if (i % k == (sum - i) % k)
        {
            printf("%lld\n", i);
            f = 0;
        }
    if (f)
        printf("Can't find the number!");
    return 0;
}

【思路2】数学解法,利用同余的性质。

先研究原题。列数学表达式如下:

(1+2+3+…+2017-n) mod 2003 = n mod 2003,所以,

(1+2+3+…+2017-n) ≡ n (mod 2003),即2017×2018/2-n与n同余。

由同余性质,两边同加n,得

2017×1009≡2n (mod 2003),注意,不能再同时除以2,因为同余不满足同除性

因为2017×1009 mod 2003 = 105,所以2n要么是105,要么是2003+105,再大则超过2017*2的范围,因为选出的数n要在1~2017范围内。2n=105舍去,因为n必须是整数;于是2n=2003+105=2108,n=2108/2=1054。

根据上述推导,如果问题变为,从1~n中选出一个数t,使1~n的和减去t之后,就模k来说同余t。可以设计算法,先求出同余的这个余数r比如105之后,要验证是否能整除2,能整除则解t=r/2;接着再让r增加k,相当于进行下一个周期的情形,再判断是否能整除2……,如此循环,直到r值超过2n。以2n为限界,是因为t最大是n,那么2t就要在2n范围内。

本题有一个坑点,即r=0,比如1~10,其中取任何一个数后,剩余的数之和都与该数在模1上同余,因为任何数都能整除1。但是,解的范围已经限定为1~n不含0,所以出解时要特判不为0。注意,不能将特判r=0时的处理放到循环外,直接令r++,因为这会改变r的枚举取值。

 

#include <cstdio>
int main()
{
    long long n, i, k, t, r, sum, f = 1;
    scanf("%lld%lld", &n, &k);
    sum = n * (n + 1) / 2;         //类似2017*1009
    r = sum % k;                   //类似105,同余的余数
    for (i = r; i < n * 2; i += k) //类似105、105+2003、105+2003+2003…
        if (i % 2 == 0 && i)       //要特判i不为0
        {
            printf("%d\n", i / 2);//类似2108/2=1054
            f = 0;//标记有解
        }
    if (f)
        printf("Can't find the number!");
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值