余数之和

F(n) = (n % 1) + (n % 2) + (n % 3) + ...... (n % n)。其中%表示Mod,也就是余数。 
例如F(6) = 6 % 1 + 6 % 2 + 6 % 3 + 6 % 4 + 6 % 5 + 6 % 6 = 0 + 0 + 0 + 2 + 1 + 0 = 3。
给出n,计算F(n), 由于结果很大,输出Mod 1000000007的结果即可。
Input
输入1个数N(2 <= N <= 10^12)。
Output
输出F(n) Mod 1000000007的结果。
Input示例
6
Output示例
3
#include <iostream>
#include <cstring>
using namespace std;

typedef long long int ll;

int MOD = 1e9 + 7;
int INV = 5e8 + 4;  
  
ll n;  
ll result = 0;  
  
ll sum(ll l, ll r)
{  
    return ((l + r) % MOD) * ((r - l + 1) % MOD) % MOD * INV % MOD;  
}  
  
int main()
{  
	cin >> n;
    result = (n % MOD) * (n % MOD) % MOD;  
    ll last = 0;
    for (ll i = 1; i <= n; i = last + 1)
    {  
        last = n / (n / i);  
        result += MOD -(n / i) * sum(i, last) % MOD;  
        result %= MOD;  
    }  
    cout << result << endl;
  
  return 0;  
}  

<think>我需要解决的问题是:给定一个整数N,将1到N的排列打乱后,形成一个排列A,然后计算每个i除以A_i的余数之和,求这个和的最大可能值。首先,我需要理解问题,然后找出如何构造这样的排列A,使得余数之和最大。 首先,余数的定义是i除以A_i的余数,也就是i mod A_i。余数的性质是,当A_i > i时,余数就是i本身;当A_i <= i时,余数是i - k*A_i,其中k是最大的整数使得k*A_i <= i。所以,余数最大的时候,可能是当A_i尽可能小,或者当A_i比i大的时候,余数是i本身。 那我们的目标是让每个i的余数尽可能大。对于每个i来说,最大的余数是多少呢?比如,当A_i = i+1时,余数是i mod (i+1) = i,这时候余数最大。但是当i=N时,i+1=N+1可能超过N的范围,所以这时候A_i只能是1到N中的一个数,所以对于i=N来说,最大的余数是N-1(当A_i=1时,余数是0?不对,N mod 1是0,这不行。或者当A_i=2时,余数是N mod 2,可能不大。那可能对于i来说,最大的余数是当A_i是i+1的时候,余数是i,但i+1必须<=N吗?比如当i=N-1时,A_i=N的话,余数是(N-1) mod N = N-1,这时候余数很大。而当i=N时,A_i只能是1到N中的一个数,这时候最大的余数可能是当A_i=1时,余数是0,这显然不好。或者当A_i=2时,余数是N mod 2,可能不大。那这时候i=N的余数可能无法很大,所以可能需要调整策略。 那可能最优的情况是,对于尽可能多的i,让A_i = i+1,这样余数是i。但当i+1超过N的时候,比如当i=N时,A_i只能是1到N中的一个数,这时候余数可能较小。所以需要找出一种排列方式,使得大部分i的余数尽可能接近i,而剩下的部分余数尽可能大。 比如,当N是偶数的时候,可以考虑将排列分成两部分:前N-1个元素排列为2,3,...,N,而最后一个元素是1。这时候,对于i=1到N-1,A_i = i+1,所以余数i mod (i+1) = i,这部分的和是1+2+...+(N-1) = N(N-1)/2。而最后一个元素i=N,A_i=1,余数是0。总和是N(N-1)/2。这可能是一个候选答案。 当N是奇数的时候,比如N=3,这时候如果排列是2,3,1。那么i=1时,A_i=2,余数1;i=2时,A_i=3,余数2;i=3时,A_i=1,余数0。总和是1+2+0=3。而另一种排列比如3,1,2,i=1时A_i=3,余数1;i=2时A_i=1,余数0;i=3时A_i=2,余数1。总和是1+0+1=2,更小。所以前面的排列更好。这时候总和是3,而N(N-1)/2=3*2/2=3,所以这时候总和等于这个值。那可能不管N是奇数还是偶数,总和都是N(N-1)/2? 那可能这个问题的解就是当排列是2,3,...,N,1的时候,余数之和是1+2+...+(N-1) +0= N(N-1)/2。那是否所有情况下这个排列都是最优的? 比如,当N=2时,排列是2,1。i=1时,余数1 mod 2=1;i=2时,余数2 mod 1=0。总和是1,而N(N-1)/2=1,符合。当N=4时,排列是2,3,4,1。i=1余数1,i=2余数2,i=3余数3,i=4余数0。总和是6,而4*3/2=6,符合。那这时候总和是N(N-1)/2。 那是否这个排列就是最优的?或者说是否存在其他排列可以得到更大的总和? 比如,当N=3时,有没有其他排列可以得到更大的总和?比如排列是3,1,2。i=1时,余数1 mod3=1;i=2时,余数2 mod1=0;i=3时,余数3 mod2=1。总和是1+0+1=2,比之前的3小。所以原来的排列更好。 那可能这个排列确实是最优的。那问题转化为,当排列是2,3,...,N,1时,余数之和是N(N-1)/2。那这是否是最大值? 那现在需要证明,对于任何排列,余数之和不超过N(N-1)/2。或者说,是否存在其他排列可以得到更大的总和? 比如,当N=5时,排列是2,3,4,5,1。余数之和是1+2+3+4+0=10,而5*4/2=10。如果尝试其他排列,比如将某个较大的数放在前面,比如排列是3,4,5,2,1。i=1时,A_i=3,余数1;i=2时,A_i=4,余数2;i=3时,A_i=5,余数3;i=4时,A_i=2,余数0;i=5时,A_i=1,余数0。总和是1+2+3+0+0=6,比10小。所以显然原来的排列更好。 那另一个例子,当N=6时,排列是2,3,4,5,6,1。余数之和是1+2+3+4+5+0=15,而6*5/2=15。如果尝试其他排列,比如将较大的数放在前面,比如排列是3,4,5,6,2,1。i=1时,余数1 mod3=1;i=2时,余数2 mod4=2;i=3时,余数3 mod5=3;i=4时,余数4 mod6=4;i=5时,余数5 mod2=1;i=6时,余数6 mod1=0。总和是1+2+3+4+1+0=11,比15小。所以原来的排列更好。 那现在的问题是,为什么这个排列能得到最大的余数之和?因为对于i=1到N-1,A_i=i+1,此时余数是i,而最后一个元素i=N的A_i=1,余数是0。这样总和是1+2+...+(N-1) = N(N-1)/2。 那是否存在其他排列,使得某些i的余数更大?比如,当i=1时,A_i=2,余数1;如果A_i=3,余数1 mod3=1,一样。所以无法更大。对于i=2,A_i=3的话,余数2;如果A_i=4,余数2 mod4=2,一样。所以对于i来说,最大的余数是当A_i=i+1的时候,余数是i。而当i+1超过N时,比如i=N,这时候无法选择i+1,所以只能选其他数,此时余数最大可能是当A_i=1的时候余数0,或者当A_i=2的时候余数N mod2,这显然比i小。 所以,这个排列确实能得到最大的余数之和,即N(N-1)/2。 那现在需要验证这个结论是否正确。比如,当N=1时,排列只能是1,余数1 mod1=0,总和0,而1*0/2=0,符合。当N=2时,总和1,符合。当N=3时,总和3,符合。当N=4时,总和6,符合。当N=5时,总和10,符合。当N=6时,总和15,符合。所以这个规律似乎成立。 那现在的问题转化为,如何证明对于任何排列,余数之和不超过N(N-1)/2,并且存在这样的排列使得余数之和等于这个值。 那现在,如何计算这个总和?对于每个i,最大的余数是当A_i=i+1时的余数i(当i+1<=N时),而当i=N时,A_i只能是1到N中的一个数,此时余数最大为0(当A_i=1时)或者其他较小的值。所以总和是sum_{i=1}^{N-1} i + 0 = (N-1)*N/2。 所以,问题的解就是这个值,即当排列是2,3,...,N,1时,余数之和为N(N-1)/2。 那现在,如何编写代码来计算这个值?因为N可能很大(1e9),所以必须用O(1)的时间复杂度。 所以,代码只需要输出N*(N-1)//2即可。 那现在,测试几个例子: 例如,输入N=3,输出3*2/2=3,正确。 输入N=4,输出4*3/2=6,正确。 输入N=5,输出5*4/2=10,正确。 输入N=1,输出0,正确。 输入N=2,输出1,正确。 所以,这个解法是正确的。</think>要最大化余数之和,我们需要构造一个排列,使得每个元素i的余数尽可能大。通过分析,当排列为[2,3,...,N,1]时,前N-1个元素的余数分别为1,2,...,N-1,而最后一个元素的余数为0,此时总和为1+2+...+(N-1) = N*(N-1)/2。 ```python n = int(input()) print(n * (n - 1) // 2) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值