noip2014 解方程(本博文转载于http://blog.csdn.net/popoqqq/article/details/40984859,略有删减)
首先阿贝尔在200年前告诉我们 五次以上方程没有求根公式 于是我们只能枚举1~m 这个是100W
然后100W再加上1W位的精度 都不用运算直接就是跪…… 怎么办呢QAQ
哈希大法好!
令f(x)=an*x^n+...+a1*x^1+a0*x^0 易知若f(x)=0 则f(x) mod p=0
反之如果f(x) mod p=0 那么我们基本可以得出f(x)=0 p比较靠谱的时候碰撞率极低
所以我们把所有的ai都对p取模 然后对于每个解O(n)验证即可
这样是O(m*n)=10 8 (不是一秒么 下一篇讨论) 可以拿到70分 p比较靠谱的话不会挂
那么100分怎么办呢?
哈希大法好!
我们很容易就会发现f(x+p) mod p=f(x) mod p
于是我们选择一个小一些的p,预处理出0~p-1所有的f(x),然后超过p的取模即可
但是p不够大会挂啊!
于是我们多选择几个p 分别取一遍mod 只有一个值对所有的p取模之后全都0才算作解
哈希大法好!Hash Killer III至今无人AC就是在证明这个算法的正确性!哈希万岁!哈希赛高!哈希万年推!
时间复杂度O(nΣp+m) 其中Σp是选择的所有质数之和 一般选择1W左右的质数就行了
const mi:array[1..7] of int64=(12537,15437,17647,14677,10003,10009,10007);
var n,m,sum,shi,x:int64;
i,j,k,y1:longint;
a:array[-1..102,-1..10000+9] of int64;
flag:array[-1..1000000+9] of boolean;
c:char;
b:array[-1..102,1..7] of int64;
f:array[-1..100000,1..7] of boolean;
begin
assign(input,'equation.in'); reset(input);
assign(output,'equation.out'); rewrite(output);
readln(n,m);
fillchar(flag,sizeof(flag),true);
fillchar(f,sizeof(f),true);
for i:=0 to n do
begin
read(c);
if c='-' then
begin j:=0; y1:=-1; end else begin y1:=1; j:=1; val(c,a[i,1],k); end;
a[i,1]:=a[i,1]*y1;
while not eoln do
begin
inc(j);
read(c);
val(c,a[i,j],k);
a[i,j]:=a[i,j]*y1;
end;
a[i,0]:=j;
readln;
end;
for k:=1 to 7 do
for i:=0 to n do
begin
shi:=1;
for j:=a[i,0] downto 1 do
begin
b[i,k]:=(b[i,k]+a[i,j]*shi mod mi[k]) mod mi[k];
shi:=shi*10 mod mi[k];
end;
end;
for k:=1 to 7 do
for i:=1 to mi[k] do
begin
sum:=0; x:=1;
for j:=0 to n do
begin
sum:=(sum+x*b[j,k] mod mi[k]) mod mi[k];
x:=x*i mod mi[k];
end;
if sum<>0 then f[i,k]:=false;
end;
sum:=0;
for i:=1 to m do
for k:=1 to 7 do
if not f[i mod mi[k],k] then begin flag[i]:=false; break; end;
for i:=1 to m do if flag[i] then inc(sum);
writeln(sum);
for i:=1 to m do if flag[i] then writeln(i);
close(input); close(output);
end.