zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    矩阵乘法优化求斐波那契
    高斯消元
    NOIP201305转圈游戏
    双六问题
    线段上格点的个数
    如何写出优雅的Python代码?
    sock.listen()
    python socket编程
    sc,sockname = sock.accept()
    格式化字符
  • 原文地址:https://www.cnblogs.com/sahdsg/p/12708261.html
Copyright © 2011-2022 走看看