题解 P1771 【方程的解_NOI导刊2010提高(01)】
emmm... 一道数论
思路
先用快速幂求出
主要过程
对于一个方程,解的个数满足:
证明过程
先来观察题目中的样例:
就是将给g(x)进行拆分分成
考虑使用隔板法
从三个位置中选取两个位置可以等效为排列组合问题,即
然后对于任意一个组合,都可以采用隔板法的思路.将其变为一个排列组合问题.
注意事项
- 只有对于40%的数据答案范围在long long范围以内,需要高精乘法和高精除法(可以不用除法)
- 注意无论是g(x)还是k都需要减1在进行计算
核心代码
- 高精度乘法(这个可能都会)
for(register int i = m ; i > n ; i--){//从n+1乘到m
for(register int j = cnt ; j >= 1 ; --j){//每一位都乘上i
ans[j] *= i;
if(ans[j] >= 10000 ) ans[j+1] += (ans[j]/10000);
ans[j] %= 10000;
}
if(ans[cnt+1] > 0) cnt++;//高精度位数增加
}
- 高精度除法(这个可能会的不多)
for(register int i = 2 ; i <= m-n ; i++){//从2除到m-n for(register int j = cnt ; j >= 1 ; --j){//每一高精度位都除i if(ans[j] % i){ long long k = ans[j]%i;//找余数 ans[j] -= k;//减去余数 ans[j-1] += (k*10000);//后一位加上余数 } ans[j] /= i;//当前一位一定可以整除了 } if(ans[cnt] == 0) cnt--;//位数减少 }
关于高精度除法的说明
对于一个数
那么
设
对于每一位都往后加,就可以进行高精度除法了
最后附上AC代码
#include <iostream>
#include <cstdio>
using namespace std;
const int mod = 1e3;
long long read(){//快读
char ch = getchar();
bool flag = true;
while(ch < '0' || ch > '9'){
if(ch == '-') flag = false;
ch = getchar();
}
long long k = ch - '0';
while(ch = getchar(),ch <= '9' && ch >= '0' ){
k = (k<<1)+(k<<3);
k += (ch-'0');
}
return flag ? k : -k;
}
long long kuai(long long num , long long k){//快速幂
if(k == 1) return num%mod;
if(k & 1){//奇数
--k;
long long now = kuai(num,k>>1)%mod;
return now*now%mod*num%mod;
}
else {//偶数
long long now = kuai(num,k>>1)%mod;
return now*now%mod;
}
}
long long ans[1000],cnt=1;//cnt表示位数
int main(){
long long k=read(),x=read();
long long g = kuai(x%mod,x);
long long n = k-1,m=g-1,w=m-n;
ans[1]=1;
for(register int i = m ; i > n ; i--){//由n+1乘到m
for(register int j = cnt ; j >= 1 ; --j){//每一位都乘上i
ans[j] *= i;
if(ans[j] >= 10000 ) ans[j+1] += (ans[j]/10000);//若大于10000 大于部分移动至下一个高精位
ans[j] %= 10000;
}
if(ans[cnt+1] > 0) cnt++;//位数增加
}
for(register int i = 2 ; i <= m-n ; i++){//从2除到m-n
for(register int j = cnt ; j >= 1 ; --j){//将每一位都除i
if(ans[j] % i){
long long k = ans[j]%i;
ans[j] -= k;
ans[j-1] += (k*10000);//将余数移动至下一个高精位
}
ans[j] /= i;
}
if(ans[cnt] == 0) cnt--;//位数减少
}
printf("%lld",ans[cnt]);//前一段单独输出(第一段不含0即不能为0004)
for(int t = cnt-1 ; t >= 1 ; t--)
printf("%04lld",ans[t]);//这里存的是4位
return 0;
}