zoukankan      html  css  js  c++  java
  • 方程的解数

    已知一个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++
  • 相关阅读:
    早晨突然想到的几句话
    VBA-工程-找不到工程或库-解决方案
    Mysql 服务无法启动 服务没有报告任何错误
    一道有趣的面试题
    异步和多线程
    异或运算
    线性代数解惑
    全文搜索引擎 Elasticsearch (一)
    HandlerExceptionResolver统一异常处理 返回JSON 和 ModelAndView
    MySQL 20个经典面试题
  • 原文地址:https://www.cnblogs.com/brilliant107/p/9403567.html
Copyright © 2011-2022 走看看