zoukankan      html  css  js  c++  java
  • 洛谷 P2312 解方程

    题目

    首先,可以确定的是这题的做法就是暴力枚举x,然后去计算方程左边与右边是否相等。

    但是noip的D2T3怎么会真的这么简单呢?卡常卡的真是熟练 你需要一些优化方法。

    首先可以用秦九韶公式优化一下方程左边的计算方法:

    左边=(((..(a[n]*x)+a[n-1])*x+..+a[1])*x+a[0]

    然后我就试着直接去算:

    #include<cstdio>
    typedef long long LL;
    LL a[110],ans[1001000];
    LL n,m,aa;
    int main()
    {
        LL i,j;
        scanf("%lld%lld",&n,&m);
        for(i=0;i<=n;i++)
            scanf("%lld",&a[i]);
        for(i=n;i>=1;i--)
            for(j=1;j<=m;j++)
            {
                ans[j]+=a[i];
                ans[j]*=j;
            }
        for(i=1;i<=m;i++)
            ans[i]+=a[0];
        for(i=1;i<=m;i++)
            if(ans[i]==0)
                aa++;
        printf("%lld
    ",aa);
        for(i=1;i<=m;i++)
            if(ans[i]==0)
                printf("%lld
    ",i);
        return 0;
    }

    然后就Wa(30)掉了...没看清数据范围(ai最长有10000位,而不是最大10000)

    也许你会想到高精度运算,但是很容易发现,这题的数据范围太大,直接高精度暴力算太慢。

    此时有一个小trick:对于每个a[n],读入的时候对某一些大质数取模。对于每个枚举出的x,就用取模过的a[i]去算。如果用对好几组对不同质数取模得到的a[i]算都能得到0,那么就认为x是合法的。

    直觉上可能觉得很容易被卡掉?但事实上一点也不容易被卡....好像还是正解..

    那么对于负的a[i]怎么去取模呢?很简单,读入的时候看一下符号位,然后按照正数的方式取模(每读入一位将当前余数乘10再加当前位再取模)。处理完整个数后,如果记录的符号位是负数,那么就将余数变为模数-余数。

    然后我去交...然后就T(70)掉了...还是太慢。(而且O2都救不了我...)

    //#pragma GCC optimize(2)
    #include<cstdio>
    #include<cstring>
    typedef long long LL;
    LL a[5][110],ans[5][1001000];
    LL prime[]={179424629,179424667,179424671,179424673,179424691};
    LL pnum=5,n,m,aa;
    char c;
    bool nok[1010000];
    int main()
    {
        //freopen("testdata.in","r",stdin);
        //freopen("testdata.ss","w",stdout);
        LL i,j,i1,fl,sl,p;
        scanf("%lld%lld",&n,&m);
        c=getchar();
        for(i=0;i<=n;i++)
        {
            while(!((c>='0'&&c<='9')||c=='-'))	c=getchar();
            if(c=='-')
                fl=1,c=getchar();
            else
                fl=0;
            for(j=0;j<pnum;j++)
            {
                for(i1=fl;c>='0'&&c<='9';i1++)
                {
                    a[j][i]=(a[j][i]*10+c-'0');
                    while(a[j][i]>=prime[j])	a[j][i]-=prime[j];
                    //ans[j][i]-=prime[j]
                    c=getchar();
                }	
                if(fl)	a[j][i]=prime[j]-a[j][i];
            }
        }
        for(p=0;p<pnum;p++)
        {
            for(j=1;j<=m;j++)
                if(!nok[j])
                    for(i=n;i>=1;i--)
                    {
                        ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
                    }	
            for(j=1;j<=m;j++)
                if(!nok[j])
                {
                    ans[p][j]+=a[p][0];
                    while(ans[p][j]>=prime[p])	ans[p][j]-=prime[p];
                }	
            for(j=1;j<=m;j++)
                if(ans[p][j]!=0)
                    nok[j]=1;
        }
        for(i=1;i<=m;i++)
            if(!nok[i])
                aa++;
        printf("%lld
    ",aa);
        for(i=1;i<=m;i++)
            if(!nok[i])
                printf("%lld
    ",i);
        return 0;
    }

    卡了很久的常之后,我放弃了,去看了题解。

    原来这个算法是可以接着优化的:http://www.cnblogs.com/NaVi-Awson/p/7566889.html

    根据的就是:f(x)≡0(modp),则f(x+p)≡0(modp)

    这样子可以快速过滤掉一些m。(怎么觉得是卡常呢...)

    然后,我又去交..又T(70)了..

    原因:质数选的太大,这样是不能筛掉什么m的

    #pragma GCC optimize(2)
    #include<cstdio>
    #include<cstring>
    typedef long long LL;
    LL a[5][110],ans[5][1001000];
    LL prime[]={179424629,179424667,179424671,179424673,179424691};
    LL pnum=5,n,m,aa;
    char c;
    bool nok[1010000];
    int main()
    {
        //freopen("testdata.in","r",stdin);
        //freopen("testdata.ss","w",stdout);
        LL i,j,i1,fl,sl,p,k;
        scanf("%lld%lld",&n,&m);
        c=getchar();
        for(i=0;i<=n;i++)
        {
            while(!((c>='0'&&c<='9')||c=='-'))	c=getchar();
            if(c=='-')
                fl=1,c=getchar();
            else
                fl=0;
            for(j=0;j<pnum;j++)
            {
                for(i1=fl;c>='0'&&c<='9';i1++)
                {
                    a[j][i]=(a[j][i]*10+c-'0');
                    while(a[j][i]>=prime[j])	a[j][i]-=prime[j];
                    //ans[j][i]-=prime[j]
                    c=getchar();
                }	
                if(fl)	a[j][i]=prime[j]-a[j][i];
            }
        }
        for(p=0;p<pnum;p++)
        {
            for(j=1;j<=m;j++)
                if(!nok[j])
                {
                    for(i=n;i>=1;i--)
                        ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
                    ans[p][j]+=a[p][0];
                    while(ans[p][j]>=prime[p])	ans[p][j]-=prime[p];
                    if(ans[p][j]!=0)
                        for(k=j;k<=m;k+=prime[p])
                            nok[k]=1;
                }
        }
        for(i=1;i<=m;i++)
            if(!nok[i])
                aa++;
        printf("%lld
    ",aa);
        for(i=1;i<=m;i++)
            if(!nok[i])
                printf("%lld
    ",i);
        return 0;
    }

    改进:可以用比较小的质数筛掉大部分m,然后用大质数筛掉剩下(也许存在的)不合法的m。

    AC代码:

    //#pragma GCC optimize(2)
    #include<cstdio>
    #include<cstring>
    typedef long long LL;
    LL a[5][110],ans[5][1001000];
    LL prime[]={81799,81817,179424671,179424673,179424691};
    LL pnum=5,n,m,aa;
    char s[10100];
    bool nok[1010000];
    int main()
    {
        //freopen("testdata.in","r",stdin);
        //freopen("testdata.ss","w",stdout);
        LL i,j,i1,fl,sl,p,k;
        scanf("%lld%lld",&n,&m);
    //	c=getchar();
    //	for(i=0;i<=n;i++)
    //	{
    //		while(!((c>='0'&&c<='9')||c=='-'))	c=getchar();
    //		if(c=='-')
    //			fl=1,c=getchar();
    //		else
    //			fl=0;
    //		for(j=0;j<pnum;j++)
    //		{
    //			for(i1=fl;c>='0'&&c<='9';i1++)
    //			{
    //				a[j][i]=(a[j][i]*10+c-'0');
    //				while(a[j][i]>=prime[j])	a[j][i]-=prime[j];
    //				//ans[j][i]-=prime[j]
    //				c=getchar();
    //			}	
    //			if(fl)	a[j][i]=prime[j]-a[j][i];
    //		}
    //	}
        for(i=0;i<=n;i++)
        {
            scanf("%s",s);
            if(s[0]=='-')
                fl=1;
            else
                fl=0;
            sl=strlen(s);
            for(j=0;j<pnum;j++)
            {
                for(i1=fl;i1<sl;i1++)
                    a[j][i]=(a[j][i]*10+s[i1]-'0')%prime[j];
                if(fl)	a[j][i]=prime[j]-a[j][i];
            }
        }
        for(p=0;p<pnum;p++)
        {
            for(j=1;j<=m;j++)
                if(!nok[j])
                {
                    for(i=n;i>=1;i--)
                        ans[p][j]=(ans[p][j]+a[p][i])*j%prime[p];
                    ans[p][j]+=a[p][0];
                    while(ans[p][j]>=prime[p])	ans[p][j]-=prime[p];
                    if(ans[p][j]!=0)
                        for(k=j;k<=m;k+=prime[p])
                            nok[k]=1;
                }
        }
        for(i=1;i<=m;i++)
            if(!nok[i])
                aa++;
        printf("%lld
    ",aa);
        for(i=1;i<=m;i++)
            if(!nok[i])
                printf("%lld
    ",i);
        return 0;
    }
  • 相关阅读:
    使用 asp.net mvc和 jQuery UI 控件包
    ServiceStack.Redis 使用教程
    HTC T8878刷机手册
    Entity Framework CodeFirst 文章汇集
    2011年Mono发展历程
    日志管理实用程序LogExpert
    使用 NuGet 管理项目库
    WCF 4.0路由服务Routing Service
    精进不休 .NET 4.0 (1) asp.net 4.0 新特性之web.config的改进, ViewStateMode, ClientIDMode, EnablePersistedSelection, 控件的其它一些改进
    精进不休 .NET 4.0 (7) ADO.NET Entity Framework 4.0 新特性
  • 原文地址:https://www.cnblogs.com/hehe54321/p/8470429.html
Copyright © 2011-2022 走看看