zoukankan      html  css  js  c++  java
  • NOIp 2014 解方程 【数学/秦九韶算法/大数取膜】By cellur925

    题目传送门

    题意:求高次方程的解及其个数。其中

    我们知道,高次方程是没有求根公式的。但是利用逆向思维,我们可以进行“试根法”,因为题目中给出了所求根的范围。但是多项式系数过于吓人,达到了sxbk的1e10000.longlong显然盛不下。只能看做字符串处理。然而即使是处理成字符串,我们也不可能真的去乘这么多。

    考虑取膜。我们把多项式系数进行取膜,它的相对效果和不取膜是一样的。(想一想,为什么)

    除了对系数取膜,我们还可以考虑对x取膜。

    - 如果 X 真的是一个根,那么取模后肯定是 0;但反之则是不确定。
    - 逆否命题:如果取模之后不是 0,那么 X 肯定不是一个根。
    - 我们就利用上面的这条性质来判断即可。

    - 考虑一个较小的模数 p
    - 如果对于 0<x<p 来说,代入 x 计算后不是 0,则那么对于 x+p
    x+2px+3p...,这些数代入计算后都不可能为 0
    - 所以我们只需要验证[1,p)之间的数,剩下的可以直接推得。

    - 时间复杂度: O(TMN)。其中 T 为模数的个数 P
    我们当然还不能仅用一个数取膜,需要多个质数(通常用质数)来提高正确率,这并不是一个精确的算法,但在大多数情况下成立。

    难道在x比较小的时候,我们计算这个多项式的值也需要暴力搞嘛?

    我们智慧的先人秦九韶早就计算了一种计算多项式的简化方法,复杂度O(n)

    (你可以在高中数学必修3中学到它)

    它大概长这样:

    它的代码大概长这样:

    1 bool check(int x,int mo)
    2 {
    3     ll num=0;
    4     for(int i=n+1;i>=1;i--)
    5         num=(num*x+a[i][mo])%prime[mo];
    6     return num==0;
    7 } 

    于是我们就可以 快速求解多项式的值了。

    至此,本题就结束了=w=。

    复杂度O(TMN),T为选取模数的个数。

    Code

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring> 
     4 
     5 using namespace std;
     6 typedef long long ll;
     7 
     8 int n,m,ans;
     9 char op[20000];
    10 int a[500][10];
    11 bool vis[2000000];
    12 int prime[10]={0,10691,14551,21871,39521,24179};
    13 
    14 void read(int pos)
    15 {
    16     bool flag=0;
    17     int st=0;
    18     scanf("%s",op+1);
    19     if(op[1]=='-') flag=1,st=2;
    20     else st=1;
    21     for(int i=st;i<=strlen(op+1);i++)
    22         for(int j=1;j<=5;j++)
    23             a[pos][j]=(a[pos][j]*10+op[i]-'0')%prime[j];
    24     if(flag)
    25         for(int j=1;j<=5;j++)
    26             a[pos][j]=(prime[j]-a[pos][j])%prime[j];
    27 }
    28 
    29 bool check(int x,int mo)
    30 {
    31     ll num=0;
    32     for(int i=n+1;i>=1;i--)
    33         num=(num*x+a[i][mo])%prime[mo];
    34     return num==0;
    35 } 
    36 
    37 int main()
    38 {
    39     scanf("%d%d",&n,&m);
    40     for(int i=1;i<=n+1;i++) read(i);
    41     for(int j=1;j<=5;j++)
    42     {
    43         int limit=min(prime[j]-1,m);
    44         for(int i=1;i<=limit;i++)
    45             if(!check(i,j))
    46                 for(int k=i;k<=m;k+=prime[j])
    47                     vis[k]=1;         
    48     } 
    49     for(int i=1;i<=m;i++)
    50         if(!vis[i]) ans++;
    51     if(!ans){printf("0");return 0;}
    52     else printf("%d
    ",ans);
    53     for(int i=1;i<=m;i++)
    54         if(!vis[i]) printf("%d
    ",i);
    55     return 0;
    56 }
    View Code

    *  开始交的时候脑子抽了以为1e6是100000于是愉快地RE了三个点233

  • 相关阅读:
    CSS实现文字上标、下标
    Inellij idea创建javaWeb以及Servlet简单实现
    利用Intellij+MAVEN搭建Spring+Mybatis+MySql+SpringMVC项目详解
    IntelliJ IDEA使用教程一 介绍&安装&配置
    JavaScript定时器实现的原理分析
    将 Django 应用程序部署到生产服务器
    html中的table导出Excel (亲测有用(●'◡'●))
    HTML用JS导出Excel的五种方法
    JS 导出网页中Table内容到excel
    Python数据库连接池实例——PooledDB
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9718509.html
Copyright © 2011-2022 走看看