[LightOJ

来源:互联网 发布:python配置opencv3.0 编辑:程序博客网 时间:2024/06/05 05:38

链接:https://vjudge.net/contest/177082#problem/G
题目:
大意是讲通过公式H(n)计算出序列总和。

解题思路:
一开始我在网上搜了很多关于这道题的题解,但始终不是很懂为什么可以这样做,以及为啥要加上特判,到后面自己打表以后才慢慢懂一些。
为了更直观一些,打表结果如下:(左边数字是n/i可能数,右边是有多少个)
这里写图片描述

根据打表结果发现:1>发现有一些元素有很多个,比如"1",那么怎么快速计算出这些元素有多少个呢?

可以根据公式:这里写图片描述 算出结果。(就是算出i到i+1之间有多少个数)
比如当n=10时,有:这里写图片描述

2>每行元素的数量与sqrt(n)大小有关,但要根据条件判断是否减1,在仔细分析表后,发现似乎与n-sqrt(n)*sqrt(n)大小有关,如下:(灵魂画图,凑合着看)

这里写图片描述

如果n-sqrt(n)*sqrt(n)<sqrt(n)的话,那么说明元素种类是奇数,因为在计算和的时候是前后一起加的,所以最后要减去多加上的n/sqrt(n)。

代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>using namespace std;typedef long long ll;#define MM(a) memset(a,0,sizeof(a))#define shutdown cin.sync_with_stdio(false);cin.tie(0);cout.sync_with_stdio(false);cout.tie(0)//int b[1001][1001];//打表专用//void init() {//    for(int i=1; i<=100; i++) {//        for(int j=1; j<=i; j++) {//            b[i][j]=i/j;//        }//    }//    for(int i=1; i<=100; i++) {//            int temp=b[i][1],flag=1;//        for(int j=1; j<=i; j++) {//            if(b[i][j+1]==temp) flag++;//            else{//                cout<<temp<<":"<<flag<<" ";//                temp=b[i][j+1];//                flag=1;//            }//        }//        cout<<endl;//    }//}ll n;ll H(ll n) {    ll res = 0;    int i,sq=sqrt(n);    for(i=1;i<=sq;i++){        res+=(n/i-n/(i+1))*i+n/i;//开头和尾部一起算    }    if(n-sq*sq<sq)//如果元素的种类是奇数        res-=n/(i-1);//减去多加的    return res;}int main() {    shutdown;//    MM(b);//    init();    int t;    cin>>t;    for(int i=1; i<=t; i++) {        cin>>n;        cout<<"Case "<<i<<": "<<H(n)<<endl;    }}
原创粉丝点击