上面那个式子,分子分母同乘一个9后,余数最终要除回一个9。
#include <cstdio>
int t;
long long x, m, k, c;
long long quickpowmod(long long x, long long y, long long mod)
{
long long ret = 1;
while(y){
if(y&1)
ret = ret*x%mod;
x = x*x%mod;
y >>= 1;
}
return ret;
}
int main()
{
scanf("%d", &t);
int cn = 0;
while(t--){
scanf("%I64d%I64d%I64d%I64d", &x, &m, &k, &c);
printf("Case #%d:\n", ++cn);
long long mod = 9*k;
long long p = quickpowmod(10, m, mod);
if((p-1)*x%mod%mod == 9*c)
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
如果对求模化简不太熟悉,可以用循环节的思路。
思路:因为是相同的数字组成的数,所以如果某一个余数之前出现过了,后面必然相同,即有循环节。所以只需要记录循环节就可以。
以下参考了大神的代码的思路:一个数 mod p,余数只能是0到p-1,这P个数,也就是说循环节最大只能是p,所以我们假定循环节就是P,就不用分别求循环节了,并且不用对一个数求余时进行讨论。
代码:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e4+50;
int t,x,c,k,res;
long long m;
int cir[maxn];///cir存储循环节
int main(){
while(scanf("%d",&t)!=EOF){
for(int cas=1;cas<=t;cas++){
memset(cir,-1,sizeof(cir));
scanf("%d%lld%d%d",&x,&m,&k,&c);
res=0;
for(int i=0;i<k;i++){
res=(res*10+x)%k;
cir[i]=res;
}
m--;///与循环节位置对齐
printf("Case #%d:\n",cas);
if(cir[m%k]==c) printf("Yes\n");
else printf("No\n");
}
}
return 0;
}
总结:遇到这种类数论题目,目前为止的解决方法有:
1、找规律,如本题可以通过寻找循环节来解决。(先想有没有最大循环节,这样可以避免讨论一些特殊的细节情况)
2、对式子进行化简转化为更容易解决的
3、想想是不是可以数位dp