P2312 解方程
知识点:枚举暴力,\(hash\) 取模
原题面
题目要求:
求方程: \(a_0 + a_1x + a_2x^2 +...+ a_nx^n = 0\) ,
在区间 \([1,m]\) 内的整数解.
分析题意:
观察数据范围:
\(0<n\le100 , m<1e6\) , 可以跑 \(O(nm)\) 的算法
\(|ai| \le 10^{10000}\) 高精会超时 的 神仙范围.
只能考虑取模运算.
-
可以发现, 假设对方程的 每个系数项进行取模后,
在 自变量取值相同的情况下 , 如果原方程右侧为\(0\) ,
那么取模后 方程的右侧仍为\(0\)即 : 对于一个多项式 \(f(x)\)
有 : \(f(x) =0 \Rightarrow f(x)\ \%\ p = 0\) -
另一个问题 :
如何在较低 的 时间复杂度内求得 \(a_0 + a_1x + a_2x^2 +...+ a_nx^n\) 的值?
考虑对式子进行转化:
\(\ \ \ \ a_0 + a_1x + a_2x^2 +...+ a_nx^n\)
\(=a_0+ x(a_1+a_2x+...+a_nx^{n-1})\)
\(=a_0+ x(a_1 + x(a_2+...+a_nx^{n-2}) )\)
\(=...\)
\(=a_0+ x(a_1+x(a_2+x(....+a_n)...)\)
明显可用递归 / 循环求解
复杂度是 \(O(n)\) 级别的,
算法实现:
可以跑 \(O(nm)\) 的算法 ,
直接暴力枚举 自变量\(x\) 的取值
再求解方程 , 检查方程右侧是否为\(0\) , 并记录合法解即可 .
算法漏洞:
类似 \(hash\) 算法 , 此解法也存在碰撞的风险.
使用不同的取模质数 , 可以取得不等的分数
但是只使用 1e9+7 可以拿到满分
为减少碰撞 概率,最好使用不同的大质数二次 取模.
双模 \(100\) 分:
#include<cstdio>
#include<ctype.h>
#define int long long
const int MARX = 1e6+10;
const int mod1 = 1e9 + 7;//两个大模数
const int mod2 = 998244353;
//=============================================================
int n,m,num , a[110],b[110],ans[MARX];
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = w*10+ch-'0';
return s*w;
}
inline void read1(int &a1 , int &b1)//快读 取模改进版
{
int s=1, w1=0,w2=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w1=(w1*10+ch-'0')%mod1,w2=(w2*10+ch-'0')%mod2;
a1=s*w1,b1=s*w2;
}
//=============================================================
signed main()
{
n=read(),m=read();
for(int i=0; i<=n; i++) read1(a[i],b[i]);//读入并二次取模
for(int i=1,sum1=0,sum2=0; i<=m; i++,sum1=0,sum2=0)//暴力枚举答案
{
for(int j=n; j; j--) sum1=((a[j]+sum1)*i)%mod1,sum2=((a[j]+sum2)*i)%mod2;//求解
sum1=(sum1+a[0])%mod1,sum2=(sum2+a[0])%mod2;
if((!sum1) || (!sum2)) ans[++num]=i;//符合要求,加入答案
}
printf("%lld\n",num);
for(int i=1;i<=num;i++) printf("%lld\n",ans[i]);
}
单模 \(1e9+7\) 卡过:
#include<cstdio>
#include<ctype.h>
#define int long long
const int MARX = 1e6+10;
const int mod = 1e9+7;
//=============================================================
int n,m,num , a[110],ans[MARX];
//=============================================================
inline int read()
{
int s=1, w=0; char ch=getchar();
for(; !isdigit(ch);ch=getchar()) if(ch=='-') s =-1;
for(; isdigit(ch);ch=getchar()) w = (w*10+ch-'0')%mod;
return s*w;
}
//=============================================================
signed main()
{
n=read(),m=read();
for(int i=0; i<=n; i++) a[i]=read();
for(int i=1,sum=0; i<=m; i++,sum=0)//暴力枚举答案
{
for(int j=n; j; j--) sum=((a[j]+sum)*i)%mod;//求解
sum=(sum+a[0])%mod;
if(!sum) ans[++num]=i;//符合答案
}
printf("%lld\n",num);
for(int i=1;i<=num;i++) printf("%lld\n",ans[i]);
}

浙公网安备 33010602011771号