A simple problem | ||
Accepted : 27 | Submit : 296 | |
Time Limit : 15000 MS | Memory Limit : 655360 KB |
Problem DescriptionThere is a simple problem. Given a number N. you are going to calculate N%1+N%2+N%3+...+N%N. InputFirst line contains an integer T, there are T(1≤T≤50) cases. For each case T. The length N(1≤N≤1012). OutputOutput case number first, then the answer. Sample Input1 5 Sample OutputCase 1: 4 Sourcedaizhenyang |
解题报告:
一道不是特别难想的题,但是要注意很多细节。
首先,求N模除1-N的和,N<=10^12,暴力是不可能的。我们可以找下规律。N%N=0,N%(N-1)=1,
N%(N-2)=2,(N较大时)。
可以发现,N 对 floor(N/2)+1到N的模除的结果依次减少1,模除的结果形成了等差数列。这是我们可以求的。
同理可以求得(N/3, N/2)区间,(N/4, N/3)区间的模除和。
这样岂不是要求到N/N?其实当(N/M)较小时,我们直接暴力求出(0, N/M)这段的模除和。
算法基本就是这样。复杂度O(sqrt(n))。
因为N很大,模除和超出了long long类型,需要使用大数。
比赛的时候思路基本就是这样,我敲的时候缺犯了一个错误:
后面的暴力和不会超过long long,而我用大数直接加上去……多一题就可以拿第二了,少了这题就是银首……
贴个代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
#include <string>
#include <set>
#include <map>
#include <queue>
#include <vector>
using namespace std;
typedef long long LL;
#define fff(i, n, m) for(int i=(n);i<=(m);i++)
#define ff(i, n) for(int i=0;i<(n);i++)
#define fout freopen
void work();
int main()
{
#ifdef ACM
fout("in.txt", "r", stdin);
#endif
work();
}
/*==============================*/
class Bignum
{
public:
int a[10];
int len;
Bignum()
{
memset(a, 0, sizeof(a));
len = 1;
}
Bignum(LL num)
{
memset(a, 0, sizeof(a));
len = 0;
while(num)
{
a[len++] = num%10000, num/=10000;
}
len = max(1, len);
}
Bignum(const Bignum & b)
{
memset(a, 0, sizeof(a));
len = b.len;
ff(i, len) a[i]=b.a[i];
}
int & operator[](int i)
{
return a[i];
}
Bignum operator+(const Bignum & b)
{
Bignum c;
c.len = max(len, b.len);
ff(i, c.len)
{
c[i] += a[i] + b.a[i];
if(c[i]>10000)
c[i+1]+=c[i]/10000, c[i]%=10000;
}
if(c[c.len]) c.len++;
return c;
}
Bignum operator*(const Bignum & b)
{
Bignum c;
c.len = len+b.len-1;
ff(i, len) ff(j, b.len)
{
c[i+j] += a[i]*b.a[j];
if(c[i+j]>10000)
c[i+j+1]+=c[i+j]/10000, c[i+j]%=10000;
}
if(c[c.len]) c.len++;
return c;
}
void print()
{
printf("%d", a[len-1]);
for(int i=len-2;i>=0;i--)
printf("%04d", a[i]);
}
};
void work()
{
int T;
scanf("%d", &T);
fff(cas, 1, T)
{
LL n;
scanf("%I64d", &n);
LL sta = n, end = n;
Bignum ans;
LL t = 1;
LL m = sqrt(n+0.0);
m = (LL)(m * 7); // 个人感觉相对较快
while(sta > m)
{
end = sta;
sta = n/(t+1);
LL r = n%end;
LL num = end - sta;
LL n1=num, n2=num-1;
if(n1%2==0) n1/=2; else n2/=2;
ans = ans + Bignum(r*num) + Bignum(n1)*Bignum(n2*t);
t++;
}
LL rr = 0;
while(sta)
{
rr+=n%sta;
sta--;
}
ans = ans+Bignum(rr);
printf("Case %d: ", cas);
ans.print();
puts("");
}
}