1. 程式人生 > >Topcoder SRM 604 div1題解

Topcoder SRM 604 div1題解

cond 代碼 簡單 let min oge 這樣的 swe possible

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 namespace
std; 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題解