描述 Description
陶陶为了给一道平面几何题出数据,需要产生 N 个点(x[i],y[i])。已知x,y是由伪随机函数顺序产生,即:
X[i+1] = (X[i]*Ax+Bx+i) mod Cx (X[1], Ax,Bx,Cx 是事先给定的)
Y[i+1] = (Y[i]*Ay+By+i) mod Cy (Y[1], Ay,By,Cy 是事先给定的)
这样,就可以快速连续产生很多点坐标(X[i], Y[i])。
不幸的是,这样产生的点有可能有相同的,虽然这种几率很少,但严谨的陶陶不允许这种事发生。陶陶要求你帮助他解决最少要产生前多少项时,正好有 N 个不相同的点。
输入格式 Input Format
第一行。一个整数 N .
第二行:4个整数 X[1]、 Ax、Bx、Cx .
第三行:4个整数 Y[1]、 Ay、By、Cy .
输出格式 Output Format
一个整数 M 。表示最少要连续产生 M 个点,正好有 N 个不相同的点。数据保证有答案。
样例输入 Sample Input
21
2 4 3 6
5 2 3 13
样例输出 Sample Output
24
时间限制 Time Limitation
1s
注释 Hint
1<=N<=1,000,000, 其它所有数据都在[0...1,000,000,000]范围内。
来源 Source
经典问题
思路:对于刚学hash的焫鷄,书上给的模板是求一个数x的查找。但这道题是求一个坐标,有两个数怎么办呢??仔细一想回发现因为你用hash存的就是一个位置,所以你可以直接让(x+y)在取模那个大的质数,然后其他操作就和普通的hash一样了。然后你高高兴兴的把程序交上去。。。(超时???)听century一说,你必须的让x和y乘一个大数相加在取模,这是为什么呢??因为在你没有乘一个大数的时候刚开始的x,y相加取模的值也不会改变,所以你前面存的点就过于密集,导致查找时时间过慢,如果你乘上一个大数,就会使这个hash变得散,所以时间复杂度就大大降低了。然后你又兴冲冲的交了上去。。。。。(wrong answer???),你会发现x1,y1为零的点你的答案都加了一??这又是为什么呢??因为你刚开始给这个结构体付的值为0,所以刚开始他就判断x1,y1为零的点已经存在了,所以你只需手动付一下x的值为-1就好了
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; const int maxprime=2323237; const int step=7; struct shadow { long long x,y,num; }hash[maxprime+5]; int q,w; int find(long long g,long long k) { int temp=(g*499979+k*299993)%maxprime; while((hash[temp].num)&&(hash[temp].x!=g||hash[temp].y!=k)) { temp+=step; if(temp>=maxprime) temp-=maxprime; } return temp; } int ans=0,h=0; void insert(long long g,long long k) { int now=find(g,k); if(hash[now].y==k&&hash[now].x==g) return; else { h++; hash[now].x=g; hash[now].y=k; hash[now].num=1; } } int main() { //freopen("add.out","w",stdout); memset(hash,0,sizeof(hash)); for(int i=0;i<=2323237+4;i++) hash[i].x=-1; int n; cin>>n; int x1,a1,b1,c1; cin>>x1>>a1>>b1>>c1; int y1,a2,b2,c2; cin>>y1>>a2>>b2>>c2; long long g=x1,k=y1; for(int i=1;;i++) { insert(g,k); g=(g*a1+b1+i)%c1; k=(k*a2+b2+i)%c2; //cout<<g<<‘ ‘<<k<<endl; ans++; if(h==n) { cout<<ans<<endl; break; } } return 0; }
<( ̄ ﹌  ̄)>