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) 

输入输出样例

输入样例#1: 复制
10
输出样例#1: 复制
9 16 22 25 29 27 29 24 21 13

说明

对于20%的数据,n1000。

对于60%的数据,n10^5。

对于100%的数据,1n10^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;
}

 如果你不开心,那我就把右边这个帅傻子分享给你吧,   

你看,他这么好看,那么深情的望着你,你还伤心吗?   

真的!这照片盯上他五秒钟就想笑了。   

一切都会过去的。

posted @ 2018-10-11 11:06  孟东行#  阅读(263)  评论(0编辑  收藏  举报