Topcoder SRM 604 div1題解
CTSC考完跑了過來日常TC~~~
Easy(250pts):
題目大意:有個機器人,一開始的位置在(0,0),第k個回合可以向四個方向移動3^k的距離(不能不動),問是否可以到達(x,y),數據滿足|x|,|y|<=10^9。
這題還是很簡單的嘛,口亨~~~
首先我們只考慮一個方向,於是發現,每一次可以移動3^k的距離或者不動,於是我們發現這樣的序列是有且僅有一個的,
於是我們分開考慮x和y,把兩個序列全部預處理出來,
然後直接掃一遍就做完了,
時間復雜度O(log|x|)左右吧,代碼如下:
1 #include <bits/stdc++.h> 2 using namespacestd; 3 class PowerOfThree 4 { 5 public: 6 string ableToGet(int x, int y) 7 { 8 x=abs(x),y=abs(y); 9 bool check=true; 10 while (x!=0||y!=0) 11 { 12 if ((x%3==0)+(y%3==0)!=1) check=false; 13 if (x%3==2) x=(x+1)/3; else x=x/3; 14 if(y%3==2) y=(y+1)/3; else y=y/3; 15 } 16 if (check) return "Possible"; else return "Impossible"; 17 } 18 };
Medium(550pts):
題目大意:有一棵n個節點的樹,有若幹節點上有一只狐貍,其它節點沒有,所有邊的距離為1。現在狐貍要聚集在一起,使得它們形成了一棵樹,且每個節點依然最多只有一只狐貍,且移動距離之和最小,輸出這個最小值。數據滿足n<=50。
我做過的最難的medium吧。。。這題做了我好久好久。。。
首先,最後形成的狐貍一定是一棵樹,我們枚舉每一個節點i,設i是最後這棵樹的root,
我們考慮樹形dp,
設f[i][j]表示i這個節點形成的子樹中一共放置了j個狐貍,且i這個節點一定有狐貍,且這j個狐貍聯通的最優值。
我們考慮如何轉移,
假設cur[j]就是當前u這個節點已經處理了若幹個兒子的f[u]數組,
於是我們能夠得到f[u][i+j]就是從已經處理的若幹個兒子中提取i個,從當前正在處理的v節點中提取j個的最優值,
那麽已經處理完的若幹個兒子對答案的貢獻度是cur[i],當前處理的v節點對答案的貢獻度是f[v][j]+(u和v這條邊對答案的貢獻度),
所以f[u][i+j]=cur[i]+f[v][j]+(u和v這條邊對答案的貢獻度),
所以我們只需要考慮這條邊的貢獻度就可以了,我們假設size[u]表示u這個節點為根的子樹下原始狀態下有多少個狐貍,
如果size[v]=j,那麽這條邊的貢獻度就是0;
如果size[v]>j,那麽一定有size[v]-j個狐貍從v這個子樹出來,那麽一定經過這條邊,所以這條邊貢獻度就是size[v]-j;
如果size[v]<j,那麽一定有j-size[v]個狐貍進入v這個子樹中,它們也一定經過這條邊,所以這條邊的貢獻度就是j-size[v]。
所以無論如何,這條邊的貢獻度一定是abs(size[v]-j)。
所以我們有f[u][i+j]=cur[i]+f[v][j]+abs(size[v]-j)。
然後邊界細節註意一下就可以了,時間復雜度O(n^4),代碼如下:
1 #include <bits/stdc++.h> 2 #define Maxn 1007 3 #define inf 1000000007 4 using namespace std; 5 int n,cnt,ans=inf,m; 6 int last[Maxn],other[Maxn],pre[Maxn],sum[Maxn],size[Maxn]; 7 int f[2*Maxn][2*Maxn]; 8 int temp[4*Maxn]; 9 bool fox[Maxn]; 10 class FoxConnection 11 { 12 void insert(int u, int v) 13 { 14 other[++cnt]=v,pre[cnt]=last[u],last[u]=cnt; 15 } 16 void dfs(int u, int fa) 17 { 18 size[u]=fox[u]; 19 int cur[4*Maxn]; 20 memset(cur,0,sizeof(cur)); 21 for (int q=last[u];q;q=pre[q]) 22 { 23 int v=other[q]; 24 if (v!=fa) 25 { 26 dfs(v,u); 27 for (int i=0;i<=m;i++) temp[i]=inf; 28 for (int i=0;i<=m;i++) 29 for (int j=0;j<=m-i;j++) 30 temp[i+j]=min(temp[i+j],cur[i]+f[v][j]+abs(size[v]-j)); 31 for (int i=0;i<=m;i++) cur[i]=temp[i]; 32 size[u]+=size[v]; 33 } 34 } 35 f[u][0]=cur[0]; 36 for (int i=1;i<=m;i++) f[u][i]=cur[i-1]; 37 } 38 int solve(int rt) 39 { 40 for (int i=1;i<=n;i++) 41 for (int j=0;j<=2*n;j++) 42 f[i][j]=inf; 43 dfs(rt,-1); 44 return f[rt][m]; 45 } 46 public: 47 int minimalDistance(vector <int> A, vector <int> B, string haveFox) 48 { 49 n=A.size()+1; 50 for (int i=0;i<n;i++) fox[i+1]=(haveFox[i]==‘Y‘); 51 m=0; 52 for (int i=1;i<=n;i++) if (fox[i]) ++m; 53 for (int i=0;i<n-1;i++) 54 insert(A[i],B[i]),insert(B[i],A[i]); 55 for (int i=1;i<=n;i++) 56 ans=min(ans,solve(i)); 57 return ans; 58 } 59 };
Hard(1000pts):
這個計算幾何題怎麽比medium思路簡單多了呢。。。
題目大意:給了你n條線段,它們可能有交點,可能有重合,現在把它們視為一個模塊,有一張10^9*10^9的長方形紙片,現在復制若幹遍這個模塊,要求任意兩個模塊不能相交,要求判斷是否可以復制無窮多份。數據滿足n<=50。
這題的思路還是很簡單的吧,如果能夠復制無數份,那麽一定是能夠往某個方向移動了很小很小的距離,
我們先把所有直線兩兩處理,
如果重合,直接不用管;
如果沒有交點,直接不用管;
如果有一個交點,而且交點不是直線的端點,直接有窮個返回答案;
如果有一個交點,而且交點是直線的端點,那麽那個方向一定有角度限制,預處理出角度限制。
所有直線兩兩處理完了之後,把所有角度限制從小到大掃一遍,然後判定一下就做完了。
時間復雜度O(n^2),代碼如下:
1 #include <bits/stdc++.h> 2 #define eps 1e-9 3 #define Maxn 107 4 using namespace std; 5 int n,cnt=0; 6 struct point {double x,y;}; 7 struct line {point a,b;}; 8 line a[Maxn]; 9 pair<double,double> cover[Maxn*Maxn*2]; 10 class FamilyCrest 11 { 12 double cross(double x1 ,double y1, double x2, double y2) 13 { 14 return (x1*y2-x2*y1); 15 } 16 bool samepoint(point a, point b) 17 { 18 //check if point a and point b are the same point 19 if (fabs(a.x-b.x)<eps&&fabs(a.y-b.y)<eps) return true; 20 return false; 21 } 22 bool sameline(line a, line b) 23 { 24 //check if line a and line b are the same line 25 double res=cross(a.a.x-a.b.x,a.a.y-a.b.y,b.a.x-b.b.x,b.a.y-b.b.y); 26 if (fabs(res)<eps) return true; 27 return false; 28 } 29 double sameposition(line a, line b) 30 { 31 //check if the whole segment b is on the same direction of line a 32 //answer>0 means segment b is on the same direction of line a 33 //answer<0 means segment b has a same point with line a 34 //answer=0 means segment b has an end point on the line a 35 double res,res1,res2; 36 res1=cross(a.b.x-a.a.x,a.b.y-a.a.y,b.a.x-a.a.x,b.a.y-a.a.y); 37 res2=cross(a.b.x-a.a.x,a.b.y-a.a.y,b.b.x-a.a.x,b.b.y-a.a.y); 38 res=res1*res2; 39 return res; 40 } 41 void updata(double l, double r) 42 { 43 if (l<r) 44 { 45 cover[++cnt].first=l,cover[cnt].second=r; 46 } else 47 { 48 cover[++cnt].first=l,cover[cnt].second=M_PI; 49 cover[++cnt].first=-M_PI,cover[cnt].second=r; 50 } 51 } 52 bool calc(line a, line b) 53 { 54 //segment a and segment b are on the same line 55 if (sameline(a,b)) return true; 56 //segment a and segment b don‘t have a same point 57 if (sameposition(a,b)>eps) return true; 58 if (sameposition(b,a)>eps) return true; 59 //segment a and segment b have a same point which is not an end point 60 if (sameposition(a,b)<-eps) return false; 61 if (sameposition(b,a)<-eps) return false; 62 //segment a and segment b have a same point which is an end point 63 point O,A,B; 64 //point O is the end point 65 if (samepoint(a.a,b.a)) O=a.a,A=a.b,B=b.b; else 66 if (samepoint(a.a,b.b)) O=a.a,A=a.b,B=b.a; else 67 if (samepoint(a.b,b.a)) O=a.b,A=a.a,B=b.b; else 68 if (samepoint(a.b,b.b)) O=a.b,A=a.a,B=b.a; 69 if (cross(A.x-O.x,B.x-O.x,A.y-O.y,B.y-O.y)>eps) swap(A,B); 70 updata(atan2(A.y-O.y,A.x-O.x),atan2(O.y-B.y,O.x-B.x)); 71 updata(atan2(O.y-A.y,O.x-A.x),atan2(B.y-O.y,B.x-O.x)); 72 return true; 73 } 74 public: 75 string canBeInfinite(vector <int> A, vector <int> B, vector <int> C, vector <int> D) 76 { 77 n=A.size(); 78 for (int i=1;i<=n;i++) 79 { 80 a[i].a.x=A[i-1]; 81 a[i].a.y=B[i-1]; 82 a[i].b.x=C[i-1]; 83 a[i].b.y=D[i-1]; 84 } 85 for (int i=1;i<=n;i++) 86 for (int j=i+1;j<=n;j++) 87 if (!calc(a[i],a[j])) return "Finite"; 88 sort(cover+1,cover+cnt+1); 89 if (cover[1].first+M_PI>eps) return "Infinite"; 90 if (cover[cnt].second-M_PI<-eps) return "Infinite"; 91 double now=cover[1].second; 92 for (int i=2;i<=cnt;i++) 93 { 94 if (cover[i].first-now>eps) return "Infinite"; 95 now=cover[i].second; 96 } 97 return "Finite"; 98 } 99 };
完結撒花~
Topcoder SRM 604 div1題解