Joseph's Problem UVALive
题意:给定n, k,求出∑ni=1(k mod i)
思路:由于n和k都很大,直接暴力是行不通的,然后在纸上画了一些情况,就发现其实对于k/i相同的那些项是形成等差数列的,于是就可以把整个序列进行拆分成[k,k/2],[k/2, k/3], [k/3,k/4]...k[k/a, k/b]这样的等差数列,利用大步小步算法思想,这里a枚举到sqrt(k)就可以了,这样就还剩下[1,k/a]的序列需要去枚举,总时间复杂度为O(sqrt(k)),然后注意对于n大于k的情况,n超过k的部分全是等于k,为(n - k) * k,这样把所有部分加起来就是答案
转载至:https://blog.****.net/accelerator_/article/details/36949761
#include <iostream> #include <cstdio> #include <sstream> #include <cstring> #include <map> #include <set> #include <vector> #include <stack> #include <queue> #include <algorithm> #include <cmath> #define MOD 2018 #define LL long long #define ULL unsigned long long #define Pair pair<int, int> #define mem(a, b) memset(a, b, sizeof(a)) #define _ ios_base::sync_with_stdio(0),cin.tie(0) //freopen("1.txt", "r", stdin); using namespace std; const int maxn = 10010, INF = 0x7fffffff; int main() { LL k, n; while(cin>> n >> k) { LL res = 0; if(n > k) res = (n-k) * k; LL a = sqrt(k), b = k/a; for(int i=a; i>1; i--) { LL a0 = k/i, an = k/(i-1); if(a0 > n) break; // 如果下限大于n 结束循环 if(an > n) an = n; // 如果上限大于n 缩小区间 res += (k % (a0+1) + k % an) * (an - a0) / 2; //求和公式 } for(int i=1; i <= n && i <= b; i++) res += k%i; cout << res <<endl; } return 0; }