Interstellar Hunter【2020CCPC秦皇島-I】
阿新 • • 發佈:2020-10-22
題意
在一個無限大的二維平面內,\(Alex\) 的起點為 \((0,0)\) 。他可以獲得若干的數對 \((a,b)\) ,使得他可以從點 \((x,y)\) 跳躍到 \((x+a,y+b)\) 或者 \((x-a,y-b)\) ,跳躍的次數不限。同時,會給出若干的點的座標 \((x,y)\),且該點處有 \(w\) 的能量可以獲得。\(Alex\) 可以選擇去獲取該點的能量或者忽略它。
\(1\leq T \leq 10^4,1\leq Q \leq 10^5,0\leq x_i,y_i\leq 10^6,1\leq w_i\leq 10^9\)
題目連結:https://codeforces.com/gym/102769/problem/I
分析
對於二維平面的可以到達的點集,可以通過構造兩個基向量來表示,即:\((X_1,Y_1)\) 和 \((0,Y_2)\) ,其中,\(Y_2\geq0,X_1\geq 0,Y1<Y_2\) 。
假設當前加入的向量為: \((a,b)\) ,首先對於合成的新向量的 \(X\) 部分,\(X_1'=gcd(X_1,a)\) ,因為 \((0,Y_2)\) 不會對 \(X\) 產生影響。可以使用拓展歐幾里得來求解,同時求出各自的係數,便於求出 \(Y_1'\)。接下來,考慮 \((X_1,Y_1)\) 和 \((a,b)\) 進行線性組合產生一個向量 \((0,d)\) ,那麼反過來,通過向量 \((X_1,Y_1)\)
求出了每次新增新向量之後的新基向量,對於給出的每個點,我們只需要判斷是否可以用基向量表示即可。複雜度:\(O(n\log(x+y))\) 。
程式碼
#include <bits/stdc++.h> using namespace std; typedef long long ll; void read(int &x) { x=0; int f=1; char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)) { x=(x<<3)+(x<<1)+ch-'0'; ch=getchar(); } x*=f; } ll gcd(ll x,ll y) { return y?gcd(y,x%y):x; } ll exgcd(ll a,ll b,ll &x,ll &y) { if(b==0) { x=1; y=0; return a; } ll res=exgcd(b,a%b,x,y); ll tmp=x; x=y; y=tmp-(a/b)*y; return res; } int main() { int T,q,cnt=0; read(T); while(T--) { read(q); int op,x,y,w; ll u=0,v=0,ans=0; ll g,X1=0,Y1=0,Y2=0; for(int i=1;i<=q;i++) { read(op); if(op==1)//向量的合成 { read(x),read(y); g=exgcd(X1,x,u,v); if(g==0) Y2=gcd(Y2,1LL*y); else Y2=gcd(Y2,(x*Y1-y*X1)/g); if(g==0) Y1=y; else Y1=Y1*u+y*v; if(Y2) Y1=(Y1%Y2+Y2)%Y2; X1=g; } else { read(x),read(y),read(w); if(X1==0)//首先滿足:x=0 { if(x!=0) continue; if(Y1==0) { if(y!=0) { if(Y2!=0&&y%Y2==0) ans+=w; } else ans+=w; } else { if(Y2==0&&y%Y1==0) ans+=w; else if(Y2!=0) { g=exgcd(Y1,Y2,u,v); if(y%g==0) ans+=w; } } } else { if(x%X1!=0) continue; if(Y2==0) { if(X1*y==x*Y1) ans+=w; continue; } if((y-(x/X1)*Y1)%Y2==0) ans+=w; } } } printf("Case #%d: %lld\n",++cnt,ans); } return 0; }