P3708 koishi的数学题
题目描述
Koishi在Flandre的指导下成为了一名数学大师,她想了一道简单的数学题。
输入一个整数n,设f(x)=∑ni=1 x mod i,你需要输出f(1),f(2)...f(n)。
按照套路,Koishi假装自己并不会做这道题,就来求你帮忙辣。
输入输出格式
输入格式:
一个正整数n。
输出格式:
一行用空格分隔的n个整数f(1),f(2)...f(n)。
输入输出样例
说明
对于20%的数据,n≤1000。
对于60%的数据,n≤10^5。
对于100%的数据,1≤n≤10^6。
这个题!简直是太毒了!
一定要纪念一下。。。
首先我们不难打出一个暴力是这样的:
(一开始还理解错了。。。)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int n,ans;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
ans=i*(n-i);
for(int j=2;j<i;++j)
ans+=i%j;
printf("%d ",ans);
}
return 0;
}
然后,,肯定T了啊。。。
大部分题解说的都是一种办法,,
但是看不懂啊!!!
smg啊。。。
然后,让我来吧。。:
我们在草纸上打出一个表,根据样例,写出i,j,i%j,和答案,如下:(n=10)
然后我们就能发现一些很神奇的事情了,,,:
1,同一行中,每一列对于上一列的数字要么大了1,要么变成了0;
2,变成0的对应的i(列数)都是它对应的j(行数)的倍数;
3,发现每个ans都是上一个ans加上n再减去这一列所有的0对应的j(行数);
是不是特别神奇!!!
所以!
我们知道了ans求得过程之后,考虑一下,
是不是只需要知道每个i(列数)下面出现的所有的0对应的j(行数)的和就好了,
然后用上一个ans+n再减去这个和就是答案了!
因为每个i(列数)下面出现的0对应的都是j(行数)的整数倍,
所以我们可以这样处理:
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i)
f[j]+=i;
然后就枚举一下,用刚刚说的,
上一个ans+n再减去这个和(也就是f[i]),完成!
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int n;
long long sum,f[1000005];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j+=i)
f[j]+=i;
for(int i=1;i<=n;i++)
{
sum=sum+n-f[i];
printf("%lld ",sum);
}
return 0;
}
如果你不开心,那我就把右边这个帅傻子分享给你吧,
你看,他这么好看,那么深情的望着你,你还伤心吗?
真的!这照片盯上他五秒钟就想笑了。
一切都会过去的。