【HAOI2008】硬币购物
既然没人写扩欧,那我就来一发吧。
扩欧也还好,就是跑的有点慢,然后写的时候还有点烦,不过还是卡过去了。
考场上看到这道题又蒙了。。。
怎么回事第一题又要爆零了?
然后我打了个暴力测了一下极限数据根本过不去(幸好没把电脑整死机)
于是想了又想,整出了个 $ O(s* t)$的扩欧算法(打了一个小时的样子)。
(话说正解好像容斥)
原本搞了下循环展开结果好像会更慢。。。
讲一下思路:用扩欧解。
安利扩欧博客:Judge's Class
预处理解之前我们要先用扩欧求出:
c1*x + c2*y = gcd(c1,c2) 中的 x和y (以及gcd),记录下来,
然后 c1、c2 除以 gcd(c1,c2)。(会扩欧的话就能懂吧。)
然后我们先 O(s log s) 预处理用 c1、c2 能拼出 s 的解。
(即 c1*x1 + c2*y1 = s 中 x1和y1 的解)
然后我们令 x1 达到最小正整数状态,即 y1 达到最大解。
这时如果 y1 为负数,则无解,将数组中的值设为-1,break。
否则我们用数组记录下此时的解。
那么 c3、c4 也是同理这样处理。
这样处理完之后我们发现如果没有 d 数组的限制,y/c2 就是方案数,
那么我们考虑一下 d1对x1 的限制 以及 d2 对 y1 的限制求出解的方案数。
然后记录答案在 f 数组里面,至于 c3、c4 就记录进 g 数组。
然后 O(s) 滚出答案。
1 //by Judge 2 #include<bits/stdc++.h> 3 #define rint register int 4 #define ll long long 5 using namespace std; 6 const int M=1e5+5; 7 #idndef Judge 8 #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 9 #endif 10 char buf[1<<21],*p1,*p2; 11 inline int read(){ int x=0,f=1; char c=getchar(); 12 for(;!isdigit(c);c=getchar()) if(c=='-') f=-1; 13 for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f; 14 } int c1,c2,c3,c4,d1,d2,x11,x22,y11,y22,d[5]; 15 int X1[M],X2[M],Y1[M],Y2[M],f[M],g[M]; 16 int ex_gcd(int a,int b,int& x,int& y){ /* 套个板子,忘了就现推 */ 17 if(!b) return x=1,y=0,a; 18 int d=ex_gcd(b,a%b,y,x); 19 return y-=a/b*x,d; 20 } 21 int main(){ 22 c1=read(),c2=read(); 23 c3=read(),c4=read(); 24 d1=ex_gcd(c1,c2,x11,y11); 25 d2=ex_gcd(c3,c4,x22,y22); 26 c1/=d1,c2/=d1,c3/=d2,c4/=d2; 27 /* 预处理出解 */ 28 for(rint s=1;s<=1e5;++s){ 29 rint tmp=s,x=x11,y=y11; 30 rint a=c1,b=c2; 31 if(tmp%d1){ 32 X1[s]=Y1[s]=-1; 33 continue; 34 } 35 tmp/=d1,x*=tmp,y*=tmp; 36 37 y+=x/b*a,x%=b; 38 if(x<0) x+=b,y-=a; 39 if(y>=0) X1[s]=x,Y1[s]=y; 40 else X1[s]=Y1[s]=-1; 41 } 42 for(rint s=1;s<=1e5;++s){ 43 rint tmp=s,x=x22,y=y22; 44 rint a=c3,b=c4; 45 if(tmp%d2){ 46 X2[s]=Y2[s]=-1; 47 continue; 48 } 49 tmp/=d2,x*=tmp,y*=tmp; 50 51 y+=x/b*a,x%=b; 52 if(x<0) x+=b,y-=a; 53 if(y>=0) X2[s]=x,Y2[s]=y; 54 else X2[s]=Y2[s]=-1; 55 } 56 for(rint T=read(),S;T;--T){ 57 ll ans=0; 58 for(int i=1;i<=4;++i) 59 d[i]=read(); 60 S=read(),f[0]=g[0]=1; 61 /* 考虑限制求出方案数 */ 62 for(rint s=1;s<=S;++s){ 63 rint tmp=s,a=c1,b=c2; 64 rint x=X1[s],y=Y1[s]; 65 if(x<0||y<0){ 66 f[s]=0; 67 continue; 68 } 69 rint maxX=min(x+y/a*b,d[1]); 70 71 if(d[2]<y) x+=(y-d[2]+a-1)/a*b; 72 if(x>maxX){ 73 f[s]=0; 74 continue; 75 } 76 f[s]=(maxX-x)/b+1; 77 } 78 for(rint s=1;s<=S;++s){ 79 rint tmp=s,a=c3,b=c4; 80 rint x=X2[s],y=Y2[s]; 81 if(x<0||y<0){ 82 g[s]=0; 83 continue; 84 } 85 rint maxX=min(x+y/a*b,d[3]); 86 87 if(d[4]<y) x+=(y-d[4]+a-1)/a*b; 88 if(x>maxX){ 89 g[s]=0; 90 continue; 91 } 92 g[s]=(maxX-x)/b+1; 93 } 94 /* O(s) 滚出答案 */ 95 for(rint i=0;i<=S;++i) 96 ans+=1ll*f[i]*g[S-i]; 97 printf("%lld\n",ans); 98 } return 0; 99 }