[BZOJ3751][NOIP2014]解方程(數學相關+亂搞)
阿新 • • 發佈:2019-01-31
題目描述
題解
顯然若
所以我們可以選上幾個質數,然後check出0-p-1之內的答案,然後由這些答案推出1-m內的答案。選上5個質數就差不多了。(抄的hzwer的質數
不過這樣的話跑得奇慢無比。算算時間複雜度應該是有一坨常數。
但是TA學長有一個我覺得更厲害並且可以證明時間複雜度的做法:首先選一個小質數p,然後處理出來0-p-1內的答案,然後推出1-m內的答案。然後再選一個大質數P,用來check所有合法的答案。
由拉格朗日定理,在0-p-1內至多隻有n個解,這樣的話不合法的答案至多會被check n 個。那麼時間複雜度可以估算為 (np+n2mp)=O(n(p+nmp))
程式碼
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1000005
int n,m,ans,aa[105],mi[105];
char a[105][10005];
bool wtf[N],is[100005];
int Mod[5]={11261,19997,22877,21893,14843};
int calc(int id,int mod)
{
int len=strlen(a[id]),A=0,st=0;
bool flag=false;
if (a[id][0]=='-') flag=true,st=1;
for (int i=st;i<len;++i)
A=(A*10+a[id][i]-'0')%mod;
return (!flag)?A:-A;
}
int main()
{
scanf("%d%d\n",&n,&m);
for (int i=0;i<=n;++i) scanf("%s",a[i]);
for (int i=1;i<=m;++i) wtf[i]=1;
for (int k=0;k<5;++k)
{
for (int x=0;x<Mod[k];++x) is[x]=1;
for (int i=0;i<=n;++i) aa[i]=calc(i,Mod[k]);
for (int x=0;x<Mod[k];++x)
{
mi[0]=1;for(int i=1;i<=n;++i) mi[i]=mi[i-1]*x%Mod[k];
ans=0;
for (int i=0;i<=n;++i) ans=(ans+aa[i]*mi[i]%Mod[k])%Mod[k];
if (ans) is[x]=0;
}
for (int x=1;x<=m;++x)
if (!is[x%Mod[k]]) wtf[x]=0;
}
ans=0;
for (int i=1;i<=m;++i)
if (wtf[i]) ans++;
printf("%d\n",ans);
for (int i=1;i<=m;++i)
if (wtf[i]) printf("%d\n",i);
}
總結
①遇到這種題各種奇技淫巧還是要想一想的。