B. Divide Candies
题意
给你一个n*n的方格,点(i,j)的权值为
i
2
+
j
2
i^2+j^2
i2+j2
问这个方格内有多少个数是m的倍数
1
<
=
n
<
=
1
0
9
,
1
<
=
m
<
=
1000
1<=n<=10^9,1<=m<=1000
1<=n<=109,1<=m<=1000
做法
由
于
m
的
数
据
范
围
很
小
,
我
们
可
以
直
接
算
出
m
∗
m
之
内
的
是
m
的
倍
数
的
个
数
由于m的数据范围很小,我们可以直接算出m*m之内的是m的倍数的个数
由于m的数据范围很小,我们可以直接算出m∗m之内的是m的倍数的个数
如
果
把
m
∗
m
这
个
矩
形
内
的
所
有
点
的
横
坐
标
+
m
,
m
的
倍
数
的
个
数
还
是
不
变
的
如果把m*m这个矩形内的所有点的横坐标+m,m的倍数的个数还是不变的
如果把m∗m这个矩形内的所有点的横坐标+m,m的倍数的个数还是不变的
纵
坐
标
同
理
,
于
是
我
们
算
出
n
∗
n
中
包
含
多
少
个
m
∗
m
,
之
后
同
理
再
算
剩
下
的
小
块
纵坐标同理,于是我们算出n*n中包含多少个m*m,之后同理再算剩下的小块
纵坐标同理,于是我们算出n∗n中包含多少个m∗m,之后同理再算剩下的小块
复
杂
度
O
(
n
l
o
g
n
)
复杂度O(nlogn)
复杂度O(nlogn)
如上图蓝色阴影用蓝色块翻倍算,红色阴影用红色块翻倍算,紫色块自己算
代码
#include<stdio.h>
typedef long long ll;
int main()
{
ll n,m;
scanf("%lld%lld",&n,&m);
ll cnt=0;
for(ll i=1;i<=m;i++)
{
for(ll j=1;j<=m;j++)
{
ll tmp=i*i+j*j;
if(tmp%m==0) cnt++;
}
}
ll ans=((n/m)*(n/m))*cnt;
cnt=0;
for(ll i=(n-n%m)+1;i<=n;i++)
{
for(ll j=1;j<=m;j++)
{
ll tmp=i*i+j*j;
if(tmp%m==0) cnt++;
}
}
ans+=2LL*cnt*(n/m);
cnt=0;
for(ll i=(n-n%m)+1;i<=n;i++)
{
for(ll j=(n-n%m)+1;j<=n;j++)
{
ll tmp=i*i+j*j;
if(tmp%m==0) cnt++;
}
}
ans+=cnt;
printf("%lld\n",ans);
return 0;
}