• BZOJ 1257 余数之和


    http://www.lydsy.com/JudgeOnline/problem.php?id=1257

    题目

    输入n,k,求[sum_{i=1}^n kmod i]

    $1leqslant n,kleqslant 10^9$

    题解

    这是一道neerc2005的题目

    如果直接算肯定超时

    $kmod i$可以写成

    [k-leftlfloor frac{k}{i} ight floor imes i]

    打表会发现$leftlfloorfrac{k}{i} ight floor$有时候会重复

    然后就是构造什么时候重复

    需要用到

    [leftlfloorfrac{k}{i} ight floorleqslant left(frac{k}{i} ight)]

    那么

    [leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floorleqslantleftlfloorfrac{k}{leftlfloorfrac{k}{left(frac{k}{i} ight)} ight floor} ight floor=leftlfloorfrac{k}{leftlfloor i ight floor} ight floor=leftlfloorfrac{k}{i} ight floor]

    [leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floorgeqslantleftlfloorfrac{k}{left(frac{k}{leftlfloorfrac{k}{i} ight floor} ight)} ight floor=leftlfloorleftlfloorfrac{k}{i} ight floor ight floor=leftlfloorfrac{k}{i} ight floor]

    所以

    [leftlfloorfrac{k}{leftlfloorfrac{k}{leftlfloorfrac{k}{i} ight floor} ight floor} ight floor=leftlfloorfrac{k}{i} ight floor]

    显然中间部分也应该相等,因为若$x<y$,那么

    [leftlfloor x ight floorleqslantleftlfloor y ight floor]

    这样就可以加速一部分,但是能加速多少呢?

    直接打表验证:

    int main() {
    	ll i=1;
    	int cnt=0;
    	while(i<int(1e9)) {
    		cnt++;
    		printf("%10lld", i);
    		i=int(1e9)/i;
    		i=int(1e9)/i;
    		i++;
    	}
    	printf("
    %d
    ", cnt);
    }
    

    得到最坏情况只有63244次循环

    那么,可以直接求和了

    [sum_{i=1}^n kmod i=nk-sum_{i=1}^n leftlfloorfrac{k}{i} ight floor imes i]

    对于每一段相等的,第二项是一个等差数列,可以过时限

    虽然不会证明时间复杂度,但是这样可以省很多证明的时间

    AC代码

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define REP(i,a,b) for(int i=(a); i<(b); i++)
    #define REPE(i,a,b) for(int i=(a); i<=(b); i++)
    #define PERE(i,a,b) for(int i=(a); i>=(b); i--)
    using namespace std;
    typedef long long ll;
    int main() {
    	int n,k; scanf("%d%d", &n, &k);
    	ll i=1, ans=(ll)n*k;
    	while(i<=n) {
    		if(i>k) {
    			break;
    		} else {
    			int j=k/(k/i);
    			if(j>n) j=n;
    			ans-=(i+j)*(k/i)*(j-i+1)/2;
    			i=j+1;
    		}
    	}
    	printf("%lld
    ", ans);
    }
    
  • 相关阅读:
    Spring 注解详解01
    java 排序算法
    Java 文件拼接器
    oracle join
    Oracle 去重
    Java 笔试面试
    Oracle 笔试题02
    jvm性能查看常用命令
    关于对JMM(java内存模型)的个人理解
    RSA前端加密后端解密避免出现明文密码
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12708261.html
Copyright © 2020-2023  润新知