码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 1363 Joseph's Problem 找规律+推导 给定n,k;求k%[1,n]的和。

时间:2017-04-26 11:49:00      阅读:178      评论:0      收藏:0      [点我收藏+]

标签:tps   line   clu   under   最大   思路   想法   ace   bre   

/**
题目:Joseph‘s Problem
链接:https://vjudge.net/problem/UVA-1363
题意:给定n,k;求k%[1,n]的和。
思路:
没想出来,看了lrj的想法才明白。

我一开始往素数筛那种类似做法想。 想k%[1,n]的结果会有很多重复的,来想办法优化。
但没走通。

果然要往深处想。

通过观察数据发现有等差数列。直接观察很难确定具体规律;此处应该想到用式子往这个方向推导试一试。

lrj想法:
设:p = k/i; 则:k%i = k-i*p;

容易想到有可能k/i==k/(i+1)

当k/i=k/(i+1); k%(i+1) = k-(i+1)*p = k - i*p - p = k%i - p; 发现等差。

如果k/j = k/i = p; 那么[i,j]区间内的值为一个等差数列。等差为-p;

如何求最大的j呢? j = k/p; 项数n = j-i+1 = k/p - i + 1 = (k-i*p)/p + 1 = (k%i)/(k/i) + 1;

首项:a1 = k%i;
公差:d = -p = -k/i;

当d = 0;说明后面的结果全部相同等于a1;
当d > 0;按照上述推导计算.


*/

#include <iostream>
#include <cstdio>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
ull getSum(ull a1,ull n,ull d)
{
    ull sum = 0;
    sum = n*a1+n*(n-1)/2*d;
    return sum;
}
int main()
{
    int n, k;
    while(scanf("%d%d",&n,&k)==2)
    {
        ull a1, m, d;
        ull ans = 0;
        for(int i = 1; i <= n; i+=m){
            a1 = k%i;
            d = -k/i;
            if(d==0){
                ans += (ull)(n-i+1)*k;
                break;
            }
            m = a1/(k/i)+1;
            m = min(m,ull(n-i+1));///k >> n的时候,不要计算多出来的结果。
            ans += getSum(a1,m,d);
        }
        printf("%llu\n",ans);

        /*ans = 0;
        for(int i = 1; i <= n; i++){
            ans += k%i;
            printf("%d\n",k%i);
        }
        printf("%llu\n",ans);
        printf("-----------\n");*/
    }
    return 0;
}

 

UVA 1363 Joseph's Problem 找规律+推导 给定n,k;求k%[1,n]的和。

标签:tps   line   clu   under   最大   思路   想法   ace   bre   

原文地址:http://www.cnblogs.com/xiaochaoqun/p/6767533.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!