洛谷P2261

来源:互联网 发布:网络上赌博输了十几万 编辑:程序博客网 时间:2024/05/07 10:52

点击看题

这道题里面,我基本上是用了找规律的方法,由于这种题是想法题,基本上只能靠意会了……

当然,我还是很良心的,出于自己语文不好,我觉得还是贴一下别人的描述吧(出处:洛古P2261题解):

假设我们要求G(p,k)(p>k),即k mod 1+ k mod 2 + k mod 3 + … +k mod p,我们可以把它分成k部分,分别是k mod ( k + 1 ) + k mod ( k + 2 ) + k mod ( k + 3 ) + … + k mod p和k mod ( k / 2 + 1 ) + k mod ( k / 2 + 2 ) + k mod ( k / 2 + 3 ) + … + k mod k和k mod ( k / 3 +1 ) + k mod ( k / 3 +2 ) + k mod ( k / 3 +3 ) + … + k mod ( k / 2 )和k mod ( k / 4 +1 ) +k mod ( k / 4 +2 ) + k mod ( k / 4 +3 ) + … + k mod ( k / 3 )和……和k mod k/k,分别记作第1部分,第2部分,第3部分……第k部分,可以证明,每一部分都是一个等差数列的和(请读者自己证明这一过程),则可用公式n·(a1+an)/2求得每个部分的值,相加即是答案。

但你会发现这种方法的时间复杂度为O(n),与直接求值的时间复杂度(O(n))相同。怎么办呢?我们可以先用直接求值的方法求出G(sqrt(p),k)的值和前sqrt(p)部分的和(sqrt(x)表示x的算术平方根用去尾法保留整数的值),可以证明,两者的和为G(p,k)(这个的证明应该很容易吧)。

那么问题来了,G(q,k)(q<k)的值是多少呢?方法与上面的类似,只是我们不用求其中一些部分,并且只要在修改一下其中一个部分即可

代码如下:

#include<cmath>#include<iostream>using namespace std;long long n,k,ans=0,i,j;int main(){cin>>n>>k;for (i=2;(double)k/i>=floor(sqrt(k))&&n>k/i;i++)ans+=(min(k/(i-1),n)-k/i)*(k%min(k/(i-1),n)+k%(k/i+1))/2;if (n>k) ans+=k*(n-k);for (j=1;j<=floor(k/(i-1))&&j<=n;j++)ans+=k%j;cout<<ans;return 0;}




0 0
原创粉丝点击