方程的解数
Posted brilliant107
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了方程的解数相关的知识,希望对你有一定的参考价值。
已知一个n元高次方程:
其中:x1, x2, …,xn是未知数,k1,k2,…,kn是系数,p1,p2,…pn是指数。且方程中的所有数均为整数。
假设未知数1≤ xi ≤M, i=1,,,n,求这个方程的整数解的个数。
输入格式:
文件的第1行包含一个整数n。第2行包含一个整数M。第3行到第n+2行,每行包含两个整数,分别表示ki和pi。两个整数之间用一个空格隔开。第3行的数据对应i=1,第n+2行的数据对应i=n。
输出格式:
文件仅一行,包含一个整数,表示方程的整数解的个数。
样例输入:
3 150 1 2 -1 2 1 2
样例输出:
178
数据范围:
1<=n<=6;1<=M<=150;
时间限制:
1000
空间限制:
65536
提示:
方程的整数解的个数小于2^31。
★本题中,指数Pi(i=1,2,……,n)均为正整数。
题解:求解的题目只能搜索,考虑n=6,爆搜6*150,要爆。再想想。。
因为是一个方程,右边等于0,考虑将左边数的一半移到右边(记得添负号),爆搜出左右两边的所有解,放入两个数组,
再分别排序,可实现O(3*150)的比较(while循环),记住一个数组中可能相同解有多个,所以要小处理一下。(见代码)
var n,m,i,j,t1,t2:longint; num,num1,ans:int64; tot,tot1:array[0..3385000]of longint; k1,k,p,p1:array[0..10000]of longint; function max(x,y:int64):int64; begin if x>y then exit(x) else exit(y); end; procedure qs(l,r: int64); var i,j,x,y: int64; begin i:=l; j:=r; x:=tot[(l+r) div 2]; repeat while tot[i]<x do inc(i); while x<tot[j] do dec(j); if not(i>j) then begin y:=tot[i]; tot[i]:=tot[j]; tot[j]:=y; inc(i);dec(j); end; until i>j; if l<j then qs(l,j); if i<r then qs(i,r); end; procedure qs1(l,r: int64); var i,j,x,y: int64; begin i:=l; j:=r; x:=tot1[(l+r) div 2]; repeat while tot1[i]<x do inc(i); while x<tot1[j] do dec(j); if not(i>j) then begin y:=tot1[i]; tot1[i]:=tot1[j]; tot1[j]:=y; inc(i);dec(j); end; until i>j; if l<j then qs1(l,j); if i<r then qs1(i,r); end; function ksm(a,b:int64):int64; var t,y:int64; begin t:=1; y:=a; while b>0 do begin if (b and 1)=1 then t:=t*y; y:=y*y; b:=b shr 1; end; exit(t); end; procedure dfs(now,sum:int64);//求左边未知数的所有解 var i:longint; begin if now>n div 2 then begin inc(num);tot[num]:=sum; exit; end;//达到未知数个数了,则记录解 for i:=1 to m do dfs(now+1,sum+k[now]*ksm(i,p[now]));//递归精妙之处,假设有两个未知数 则sum的值是1,1 1,2 2,1 2,2(前属数组省略)能把所有可能记录 end; procedure rdfs(now,sum:int64);//数组和变量最好不要定义太相似,因为错了找错很麻烦,这里我调了好久,比如tot,tot1; num,num1; 下次注意; var i:longint; begin if now>n-(n div 2) then begin inc(num1);tot1[num1]:=sum; exit; end; for i:=1 to m do rdfs(now+1,sum+k1[now]*ksm(i,p1[now])); end; begin readln(n); readln(m); for i:=1 to n do readln(k[i],p[i]); for i:=n div 2+1 to n do begin inc(j); k1[j]:=-1*k[i]; p1[j]:=p[i]; end; dfs(1,0);//要用搜索,因为不知道一边有几个未知数,for循环不行 rdfs(1,0); qs(1,num); qs1(1,num1); i:=1;j:=1; while (i<=num)and(j<=num1) do begin if tot[i]=tot1[j] then begin//小处理 t1:=1;t2:=1; while (tot[i+1]=tot1[j])and(i<=num) do begin inc(i);inc(t1); end;//i+1是为了让下一位还是原来的数值 while (tot[i]=tot1[j+1])and(j<=num1) do begin inc(j); inc(t2);end; ans:=ans+t1*t2; inc(i);inc(j); end else if tot[i]>tot1[j] then inc(j) else inc(i); end; writeln(ans); end.
以上是关于方程的解数的主要内容,如果未能解决你的问题,请参考以下文章