方程的解数

已知一个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;
2.GIF

 

时间限制:

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.
NOIP2018 rp++
原文地址:https://www.cnblogs.com/brilliant107/p/9403567.html