首页 > 代码库 > POJ 2800 Joseph’s Problem 数论找规律

POJ 2800 Joseph’s Problem 数论找规律

Description 
技术分享 
Input 
两个整数n和k(1<=n,k<=1e9) 
Output 
输出技术分享 
Sample Input 
5 3 
Sample Output 

暴力超时,这样就打下表找下余数的规律。输入100,27,一下子就可以看出来,倒着的看,是一段一段的等差序列。

例如100 25

除数 1    2    3    4    5    6    7    8    9     10     11    12   13 14  15  ......25   26........

 商  25  12   8    6    5    4    3    3    2     2       2      2      1   1   1   ........1    0.....

 

这里可以看到商的变化前面很大,从5后面开始稳定下来,观察,其实就是sqrt(k),前面除数数小,商的变化就大,这个临界点也与求质数打表那个相似,从2~sqrt(质数),遍历判断,如果没有能整除的即为质数,这两个的数学原理好像是相同的,想想为什么?

 

sqrt(k) = e;

然后我们利用除数来求等差数列的区间。也就是枚举商sqrt(k)~1,左区间p1 =  k/e+1,得的是左区间,然后k/(e-1)得右区间,注意e这个除数其实不是起点,得到相同商的第一个起点是e+1,然后利用e-1得到这个相同的商的最大的一个除数,比如25/3=8,这个等差区间的最后一个,25/2=12,这个等差区间的最后一个。

除数i大于k的部分,数量是n-k,然后直接k*(n-k)

小于sqrt(k)的部分直接枚举就行了

 

****然后之前还有一个问题,按照HJ的写发,p1是k/e,是相同商的前一个区间的最后一个数,所以求和公式,数量不用+1,但是上底+1,再加下底,他的这个写发有一个问题是:

上面例子 n=8的时候,3 3这两个商的区间在i=4的时候算完了,然后i=3,p1=8,p2=12大于n了,p2=8,然后求和相减等于0,这部分其实多算了一遍,区间就已经没有了。跳出的上一个循环肯定是完成了p2=n的操作。比如继续p1=25/2=12明显大于n了,跳出。按照我这种写法,n=8,算完除数为3的,p1=9直接跳出了。********

总思想其实就是:这个等差序列的第一个是前一个等差序列最大除数的下一个,最后一个就是这个等差序列的最大除数,在代码的循环里面也是循环到2就结束,因为2算的就是商为1的情况。

 

#include <bits/stdc++.h>using namespace std;typedef long long ll;int main(){    freopen("joseph.in","r",stdin);    freopen("joseph.out","w",stdout);    ll n,k;    while(~scanf("%I64d%I64d",&n,&k))    {        ll sum=0;        //第三部分        if(n>k)            sum+=(n-k)*k;        ll e=sqrt(1.0*k);        ll p=k/e;        //第一部分        for(int i=1;i<=n && i<=p;i++)            sum+=k%i;        //第二部分        for(int i=e;i>1;i--)        {            ll p1=k/i + 1;            ll p2=k/(i-1);            //n小于左区间了就直接退出了            if(p1>n)                break;            //当n的大小小于这段等差数列区间的最后一个值            if(p2>n)                p2=n;            sum+=(k%(p1)+k%p2)*(p2-p1+1)/2;//等腰求和        }        printf("%I64d\n",sum);    }    return 0;}

 

POJ 2800 Joseph’s Problem 数论找规律