题目描述
佳佳碰到了一个难题,请你来帮忙解决。
对于不定方程a1+a2+…+ak-1+ak=g(x),其中k≥2且k∈N,x是正整数,g(x)=x^x mod 1000(即x^x除以1000的余数),x,k是给定的数。我们要求的是这个不定方程的正整数解组数。
举例来说,当k=3,x=2时,分别为(a1,a2,a3)=(2,1,1)'(1,2,1),(1,1,2)。
输入输出格式
输入格式:
输入文件equation.in有且只有一行,为用空格隔开的两个正整数,依次为k,x。
输出格式:
输出文件equation.out有且只有一行,为方程的正整数解组数。
输入输出样例
输入样例#1:
3 2
输出样例#1:
3
说明
对于40%的数据,ans≤10^16;对于100%的数据,k≤100,x≤2^31-1,k≤g(x)。
_NOI导刊2010提高(01)
分析:考虑dp,设f[i][j]表示选了i个数,和为j的正整数解组数.很显然f[i][j]=∑f[i-1][j-kk],kk是i能够取到的数,答案是f[x^x % 1000][k].复杂度是三次方级别的,看有没有方方法来优化一下.单纯从dp上来看似乎是只能优化空间了,如果有公式就好了,类似青蛙过河一样。
其实问题可以变成我们要走k步,每一步走的距离任意,走的总距离要为x,求方案数,因为每一步走的距离任意,实际上我们只要把这k步分配到x中就好了.把x抽象成x个点,画在图上,就能发现走k步实际上是在x-1个间隔中找k-1个间隔,那么答案就是C(x-1,k-1).
因为k,x很大,所以要用到高精度,我用结构体写高精度总是出现奇怪的错误,以后还是用数组了.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; long long k,x; int f[1000][110][220]; long long qpow(long long a,long long b,int mod) { long long ans = 1; while (b) { if (b & 1) ans = (ans * a) % mod; a = (a * a) % mod; b >>= 1; } return ans; } void add(int x,int y,int x1,int y1,int x2,int y2) { for (int i = 1; i <= max(f[x1][y1][0],f[x2][y2][0]); i++) { f[x][y][i] += f[x1][y1][i] + f[x2][y2][i]; f[x][y][i + 1] = f[x][y][i] / 10; f[x][y][i] %= 10; } f[x][y][0] = max(f[x1][y1][0],f[x2][y2][0]); if (f[x][y][f[x][y][0] + 1]) f[x][y][0]++; } int main() { scanf("%lld%lld",&k,&x); x = qpow(x,x,1000); for (int i = 0; i < x; i++) f[i][0][0] = f[i][0][1] = 1; for (int i = 1; i < x; i++) for (int j = 1; j < k; j++) add(i,j,i-1,j,i-1,j-1); for (int i = f[x-1][k-1][0]; i >= 1; i--) printf("%d",f[x-1][k-1][i]); printf(" "); return 0; }