【codevs3732】【BZOJ3751】解方程,hash+秦九韶算法

传送门1
传送门2
写在前面:傻逼字符串毁我青春,颓我精神
思路:
30分:直接暴力1-m枚举就行,每次进行n次运算,然后验证即可,时间复杂度O(nm)
50分:在30分的基础上加上高精度(听Shallwe说重载比写函数更可以减少本题所需的加,减,乘多重高精运算带来的巨大代码量与编程难度),并尽量使用秦九韶算法,时间复杂度最大应该是O(10^7-10^8),应该要更小些?
链接:
秦九韶算法百度百科
我的模板
70分:不加高精改为对ai取模,然后30分做法就可以了,对于能不能得到70需要看mod的质量(大质数好些)和血统
100分:O(nm)在这里最高会达到10^8,加上一些乱七八糟的常数显然是过不了的,这里就要让m变小一些,我们可以把70分中的想法再延伸,很显然当方程左边在mod p的情况下时,x 与 x+p的结果是一样的,那么我们就可以通过取模把m变小,为了提高准确度要多取几个mod,同时也不能取太多导致超时,在准确度和时间复杂度中做到平衡,大约取5个10000-20000的素数就可以了,如果x=i时在所有mod的情况下仍为0,那么就把i加到答案里,总时间复杂度大约在是O(nk*len(ai)+npk+km),k为mod的总数,p是所有mod的平均数
注意:
1.算法无误的情况下,如果OLE一般是hash取得不好(比如我),毕竟不是每个人都是欧洲细作,换一组就好(选的是黄学长的)

2.BZOJ上数据有毒!真的有毒!scanf(“%s”,s)能A,然而gets(s)就会WA!

#include"bits/stdc++.h"
using namespace std;
int n,m;
char s[10010];
int ans[100010],a[101][6],b[100010][6];
bool sign[10010];
int prime[6]={0,11261,19997,22877,21893,14843};
main()
{
    scanf("%d%d\n",&n,&m);
    for (int i=0;i<=n;i++)
    {
        scanf("%s",s);
        int l=strlen(s);
        if (s[0]=='-') sign[i]=1;
        for (int p=1;p<=5;p++)
        {
            for (int j=sign[i];j<l;j++)
            a[i][p]=(a[i][p]*10+s[j]-'0')%prime[p];
            if (sign[i]) a[i][p]=-a[i][p];
        }
    }

    for (int p=1;p<=5;p++)
    for (int i=1;i<=min(m,prime[p]-1);i++)//网上有些代码是从0开始循环的,其实是不对的,因为取得是1-m的整数解,不过不知道为何无论是原数据还是加强的都没有卡这里
    {
        b[i][p]=a[n][p];
        for (int j=n-1;j>=0;j--)
        b[i][p]=(b[i][p]*i+a[j][p])%prime[p];
    }//秦九韶

    for (int i=1;i<=m;i++)
    {
        bool flag=0;
        for (int j=1;j<=5;j++)
        if (b[i%prime[j]][j])
        {flag=1;break;}
        if (!flag) ans[++ans[0]]=i;
    }
    printf("%d\n",ans[0]);
    for (int i=1;i<=ans[0];i++)
    printf("%d\n",ans[i]);
}

你可能感兴趣的:(【codevs3732】【BZOJ3751】解方程,hash+秦九韶算法)