【NOIP2014 Day2 T3解方程】很神奇的分块枚举大法
我们可以想到,这道题ai模一个大质数之后,原来能够满足方程成立的解x仍然能够成立,但是也会出现一些原来不能使得方程成立的x极小概率使方程成立。由于我们模一个比较优秀的大质数(比如不是常被卡的1e9+7虽然我写的仍然是1e9+7,但是想到不这样,这道题就没法做了,可见ccf还是挺良心的)
第一种做法,直接枚举x进行判断,写起来十分简便容易,时间复杂度O(nm)能够get到70分
第二种做法,不知道标算是否是这样的,但且当其为标算来看,思想类通分块BSGS(传送门: http://www.newuser.top/2018/03/20/poj2417-discrete-logging%EF%BC%88%E9%AB%98%E6%AC%A1%E5%90%8C%E4%BD%99%E6%96%B9%E7%A8%8B%EF%BC%89/)。
我们可以模过大质数后再模一个质数,得到b1,b2,b3.....
bi=ai (mod p)
然后枚举[0,p-1]中的x,不会超过n个。
之后再枚举[1,m]的x中mod p 后满足上面的方程的 x在代入模大质数后的方程里面进行判断。
时间复杂度O(np+n^2(m/p)),可知当p=sqrt(nm)时,时间复杂度(n sqrt(nm) )
talk is cheap , show me code:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<map>
#include<cmath>
#define dzs (1000000007)
#define ll long long
using namespace std;
ll p; ll a[105],n,m,b[105];
void R(ll x)
{
bool mark=0;
a[x]=b[x]=0;
char ch=getchar();
while((ch>'9'||ch<'0')&&(ch!='-')) ch=getchar();
if(ch=='-') mark=1;
else a[x]=b[x]=ch-'0';
ch=getchar();
while(ch>='0'&&ch<='9'){ a[x]=((a[x]<<3)+(a[x]<<1)+ch-'0')%dzs; b[x]=((b[x]<<3)+(b[x]<<1)+ch-'0')%p; ch=getchar(); }
if(mark) {a[x]=-a[x]; b[x]=-b[x];}
}
bool dra(ll x)
{
ll rez=0;
for(ll i=n;i>=0;i--)
{
rez=(rez*x+a[i])%dzs;//qjz dalao
}
if(!rez) return true;
else return false;
}//寻找到比较优秀的小质数
bool drb(ll x)
{
ll rez=0;
for(ll i=n;i>=0;i--)
{
rez=(rez*x+b[i])%p;//qjz dalao
}
if(!rez) return true;
else return false;
}
ll findzs(ll from)
{
if(from==2) return from;
for(;from<=m;from++)
{
for(ll i=2;i<=(ll)sqrt(from);i++)
{
if(from%i==0) goto aha;
}
return from;
aha:continue;
}
from--;
return from;
}
ll ans[10000005],tot;
bool sz[10000005];
int main()
{
scanf("%lld%lld",&n,&m);
p=sqrt(n*m);
p=findzs(p);
for(ll i=0;i<=n;i++)
{
R(i);
}
for(ll i=0;i<=p-1;i++)
{
if(drb(i)) sz[i]=1;
}
for(ll i=1;i<=m;i++)
{
if(sz[i%p])
{
if(dra(i))
{
ans[++tot]=i;
}
}
}
printf("%lld\n",tot);
for(ll i=1;i<=tot;i++)
printf("%lld\n",ans[i]);
} //应该是标算了。。。。

浙公网安备 33010602011771号