CODEVS 3732: [NOIP2014]解方程
Time Limit: 1 Sec Memory Limit: 128 MB
Description

Input
输入共n+2行。
第一行包含2个整数n、m,每两个整数之间用一个空格隔开。
接下来的n+1行每行包含一个整数,依次为a0,a1,a2,……,an。
Output
第一行输出方程在[1, m]内的整数解的个数。
接下来每行一个整数,按照从小到大的顺序依次输出方程在[1, m]内的一个整数解。
Hint

【数论噩梦系列】%%%数学省队同桌
--------------------------------0-------------------------------
妈呀这题我不会【滑稽再见】。
-------------------------------30-------------------------------
CCF的30%枚举拿拿还是很开心的【括弧笑】。
-------------------------------50-------------------------------
50%高精模拟?
听说某位线段树大师写挂了2333。
----------------------------思考人生----------------------------
怎么搞呢?
脑子想想都觉得100%高精不靠谱(高精加减乘方复杂度怎么看就愉♂悦)。
把范围缩小?
有没有听过这样一句话:由于XXXX的方案数太多,输出时要对100000007取模。
好熟悉的梗!
于是Get了一个新姿势:
-------------------------------70-------------------------------
选取几个较大素数(例如10000-20000之间的)
对于每个x,算出f(x)%pi,如果f(x)=0则f(x)%pi必然=0,多选几个素数,就可以在一定范围大小内判断成功。
但是不够快QAQ
-------------------------二段思考人生--------------------------
70拿拿也蛮好的,就当总分570做!
不对,这是练习,不是比赛现场。
搜题解:【定理:f(x)≡f(x+p)%p 这里f(x)为整系数多项式】
真TM机智!(二项式定理可以眼秒证明)
------------------------------100-------------------------------
对于一个x,f(x)≠0(mod p),则x+p,x+2p……均不为方程的解。
筛法大法好!
------------------------------150-------------------------------
m<=10^8
https://vijos.org/p/1915/solution @doc @sujiao
100分脑残Code:
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define M 110
#define R 6
#define G getchar()
using namespace std;
int a[10005],A[M],P[R]={30011,11261,14843,19997,10007,21893},N,H[M][R],L,S=0,V,p,X,sum,x,n,m,W;
bool C[1000005];char ch;
int main()
{
scanf("%d%d\n",&n,&m);
for (int i=0;i<=n;i++)
{
L=0;
if ((ch=G)=='-') N=-1;
else a[L++]=ch-48,N=1;
while ((ch=G)>47)a[L++]=ch-48;
scanf("\n");
for (int p=0;p<R;p++)
{
W=0;
for (int w=0;w<L;w++)W=(W*10+a[w])%P[p];
H[i][p]=(P[p]+W*N)%P[p];
}
}
for (int i=1;i<=m;i++)
{
V=1;
if (C[i]) continue;
for (int j=0;j<R;j++)
{
p=P[j],x=i%p,sum=0,X=1;
for (int k=0;k<=n;k++) sum=(sum+X*H[k][j])%p,X=(X*x)%p;
if (sum)
{
for (int k=i;k<=m;k+=P[j])C[k]=1;
V=0;break;
}
}
if (V) A[++S]=i;
}
printf("%d\n",S);
for (int i=1;i<=S;i++)
printf("%d\n",A[i]);
return 0;
}
150分Code:(由于O(n^3+n*sqrt(m))导致常规数据下比O(m)慢)
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 110
#define pri 4
using namespace std;
typedef long long LL;
int a[10010],prime[4]={10007,10009,12007,13001},neg,hehe[110][4],l;
int s[110][2],la[2],anss[110],ans;
char ch;
void gcd(LL a,LL b,LL& d,LL& x,LL &y)//ax+by=d
{
if (!b)d=a,x=1,y=0;
else gcd(b,a%b,d,y,x),y-=x*(a/b);
}
LL CRT(LL a1,LL p1,LL a2,LL p2)//%a1=p1 %a2=p2
{
LL s=a2-a1,k1,k2,pp=p1*p2,d;
gcd(p1,-p2,d,k1,k2);
s=(s%pp+pp)%pp;
k1=(k1%pp+pp)%pp;
//d=1;
k1=k1*s%pp;
return (k1*p1%pp+a1%pp)%pp;
}
int main()
{
int n,m;
scanf("%d%d\n",&n,&m);
for (int i=0;i<=n;i++)
{
l=0;
ch=getchar();
if (ch=='-') neg=-1;
else {a[l++]=ch-48;neg=1;}
ch=getchar();
while (ch<=57&&ch>=48)
{
a[l++]=ch-48;
ch=getchar();
}
scanf("\n");
for (int p=0;p<pri;p++)
{
int ans=0;
for (int w=0;w<l;w++)
ans=(ans*10+a[w])%prime[p];
hehe[i][p]=(prime[p]+ans*neg)%prime[p];
}
}
int ans=0;
for(int A=0;A<2;A++)
{
for (int i=1;i<=prime[A];i++)//枚举答案
{
int p=prime[A],x=i%p,sum=0,X=1;
for (int k=0;k<=n;k++)//
sum=(sum+X*hehe[k][A])%p,X=(X*x)%p;
if (!sum) {s[++la[A]][A]=i;}
}
}
for(int I=1;I<=la[0];I++)
for(int J=1;J<=la[1];J++)
{
int vic=1,i=CRT(s[I][0],prime[0],s[J][1],prime[1]);
if(i>m)continue;
for (int j=0;j<pri;j++)//判素数
{
int p=prime[j],x=i%p,sum=0,X=1;
for (int k=0;k<=n;k++)//
sum=(sum+X*hehe[k][j])%p,X=(X*x)%p;
if (sum)
{
vic=0;
break;
}
}
if (vic) {anss[++ans]=i;}
}
if(!ans)puts("0");
else
{
sort(anss+1,anss+1+ans);
printf("%d\n",ans);
for (int i=1;i<=ans;i++)
printf("%d\n",anss[i]);
}
return 0;
}
2015年11月05日 21:44
%%%快去做解方程加强版!
https://vijos.org/p/1915