[BZOJ2742/Luogu4598][HEOI2012]Akai的数学作业

题目链接:

BZOJ2742

Luogu4598

好想吐槽某谷评分制度。。为什么我评个蓝之后从紫变成了黑。。。

首先,设解\(x=\frac{p}{q}(Gcd(p,q)=1)\)

那么就有\(\sum_{i=0}^n\limits a_ix^i=0\)

\(\sum_{i=0}^n\limits a_i(\frac{p}{q})^i=0\)

乘以\(q_i\)通分:\(\sum_{i=0}^n\limits a_ip^iq^{n-i}=0\)

那么可以推导出:

\(\sum_{i=0}^n\limits a_ip^iq^{n-i}\equiv a_0q^n\equiv 0(mod\ p)\)Mark

\(\sum_{i=0}^n\limits a_ip^iq^{n-i}\equiv a_np^n\equiv 0(mod\ q)\)

因为\(p,q\)互质那么得到结论:\(p|a_0,q|a_n\)

暴力枚举\(p,q\)代入方程判断合法即可。

如何判断?可以选取一个模数看两边在同余系下是否相同(详情可以参考Luogu2312解方程

不放心可以多选几个进行测试。

还有几个需要注意的问题:

\(a_0=0\)怎么办?怎么枚举\(p\)

找到一个最小的\(i\)使得\(x_i\not=0\),那么枚举\(x_i\)的因子即可(此时上文推导Mark处的\(mod\ p\)就变成了\(mod\ p^{i+1}\)

第二是要判断负数解,即\(-\frac{p}{q}\)

最后需要特判最终解\(x=\frac{p}{q}=0\)的情况(即\(a_0=0\))。

时间复杂度:能过

代码:

#include <cstdio>
#include <vector>
#include <algorithm>
typedef long long ll;

inline int Abs(const int x){return x>=0?x:-x;}
int Gcd(const int a,const int b){return b?Gcd(b,a%b):a;}
ll Pow(ll a,ll b,const int p)
{
    ll Res=1;
    for(;b;b>>=1,a=a*a%p)
        if(b&1)Res=Res*a%p;
    return Res%p;
}
int n,a[105];
const int Mod=1000000007;
struct Fraction
{
    int p,q;
    inline bool operator<(const Fraction &o)const
    {return (double)p/q<(double)o.p/o.q;}//分数 p为分子 q为分母
};
std::vector<int> Factor[2];//a[0](a[i])和a[n]的因子
std::vector<Fraction> Answer;

void Get_Factor(const int Number,std::vector<int> &Result)//求Number的因子,存放在Result中
{for(int i=1;i<=Number;++i)if(Number%i==0)Result.push_back(i);}//O(N)遍历已经足够

void Check_Answer(int p,int q)//判断解可行性
{
    ll g=Gcd(Abs(p),Abs(q)),xs=1,Value=0,x=p*Pow(q,Mod-2,Mod)%Mod;
    if(g>1)return;//防止解重复,如1/2,2/4,3/6...
    for(int i=0;i<=n;++i)
    {
        Value=(Value+a[i]*xs)%Mod;
        xs=xs*x%Mod;
    }
    if(!Value)Answer.push_back((Fraction){p,q});
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<=n;++i)scanf("%d",&a[i]);
    for(int i=0;i<=n;++i)
        if(a[i]!=0)Get_Factor(Abs(a[i]),Factor[0]),i=n;
    Get_Factor(Abs(a[n]),Factor[1]);
    if(!a[0])Answer.push_back((Fraction){0,1});
    for(int i=0;i<(int)Factor[0].size();++i)
        for(int j=0;j<(int)Factor[1].size();++j)
        {
            Check_Answer(+Factor[0][i],Factor[1][j]);
            Check_Answer(-Factor[0][i],Factor[1][j]);
        }
    std::sort(Answer.begin(),Answer.end());
    printf("%d\n",(int)Answer.size());//按要求输出解
    for(int i=0;i<(int)Answer.size();++i)
        if(Answer[i].q==1)printf("%d\n",Answer[i].p);
        else printf("%d/%d\n",Answer[i].p,Answer[i].q);
    return 0;
}

转载于:https://www.cnblogs.com/LanrTabe/p/10497673.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值