题目链接
https://codeforces.com/problemset/problem/1213/C
解题思路
最初的思路:
枚举n/m的商,同时统计所枚举到的商与m的乘积对10取模得到的每种个位的数量;单独一个10次的循环,统计ans。
方法没错,但是时间不够,如果n很大而m很小,时间复杂度最高可以到1e16。
大佬的思路:
我们要找能整除m的数,那么这些数一定可以表示为x*m
且x<=n/m
我们可以发现1*m%10=11*m%10=21*m%10=……=111*m%10=121*m%10=……
,只要x的个位相等,那么这些x与乘以m之后的个位也相等。
小证明一下:一个数A由n位组成,从高位到低位的每一个数字为a[n-1],a[n-2],a[n-3],……,a[1],a[0]
,
A的大小为a[n-1]*10^(n-1)+a[n-2]*10^(n-2)+……+a[1]*10^1+a[0]*10^0
由取模运算规则可得,
A%10 = ( a[n-1]*10^(n-1)+a[n-2]*10^(n-2)+……+a[1]*10^1+a[0]*10^0 )%10 = ( a[n-1]*10^(n-1) )%10 + ( a[n-2]*10^(n-2) )%10 + …… + ( a[1]*10^1 )%10 + ( a[0]*10^0 )%10 = a[0]
证明完了。
想表达的就是,任意的x*m
其中x<=n/m
,只要x的个位相等,那么x*m
的个位也相等。
这样一来我们就不用像最初思路那样,把所有的x都枚举一遍了。
我们只需要统计一下x=1~9
时x*m
的个位是什么就行了。
再统计一下x<=n/m
的范围内,x的个位为1~9
的数量,用数量乘以权重(即x=1~9
范围内x*m
的个位的值),求和,结束。
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; int T; ll n,m,cnt[10],ans; int main() { cin>>T; while(T--) { ans=0;memset(cnt,0,sizeof cnt); cin>>n>>m; ll aa=n/m%10; ll bb=n/m/10; for(int i=1;i<=9 && i*m<=n;i++)//求权重,对应解题思路中x=1~9,x*m的个位;即cnt[x]=x*m%10 cnt[i]=i*m%10; for(int i=1;i<=9;i++) ans+=cnt[i]*(i<=aa?bb+1:bb);//如果我们枚举的个位比最后n/m的个位大,那么数量就只有n/m/10个,否则会多一个;举个例子,假设n/m(即解题思路中x<=n/m的x的最大值)为21,则个位为1的为1,11,21,但是个位为2的只有2,12,同样,个位为3的只有3,13 cout<<ans<<endl; } }
总结
凡是沾点数论知识的都不会,看题解也得看半年!!wsfw