首页 > 代码库 > Topcoder SRM 608 div1 题解

Topcoder SRM 608 div1 题解

Easy(300pts):

题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限。现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需要选择多少个盒子。数据满足n<=50。

首先第一个方面,如果我们选择的盒子的下限大于等于X,那么显然我们一定可以获得那么多的苹果,

所以我们将盒子的下限排序,然后从大到小累加即可。

另一方面,如果我们没有选择的盒子的上限小于等于S-X,那么显然我们也一定可以获得那么多的苹果,

于是我们再按照上限排序,然后扫一遍累加即可。

时间复杂度O(nlogn),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxn 57
 3 using namespace std;
 4 int n;
 5 int l[Maxn],r[Maxn];
 6 class MysticAndCandies
 7 {
 8     public:
 9     int minBoxes(int C, int X, vector <int> low, vector <int> high)
10     {
11         n=low.size();
12         for (int i=1;i<=n;i++) l[i]=low[i-1];
13         for (int i=1;i<=n;i++) r[i]=high[i-1];
14         sort(l+1,l+n+1);
15         sort(r+1,r+n+1);
16         for (int i=1;i<n+1-i;i++) swap(l[i],l[n+1-i]),swap(r[i],r[n+1-i]);
17         int ans,sum1=0,sum2=0;
18         for (int i=1;i<=n;i++) sum2+=r[i];
19         for (ans=1;ans<=n;ans++)
20         {
21             sum1+=l[ans];
22             sum2-=r[ans];
23             if (sum1>=X||C-sum2>=X) break;
24         }
25         return ans;
26     }
27 };

Medium(600pts):

题目大意:给出一个n个点的有向图,假设长度为L的路径一共有S条(路径可以经过重复的点多次,S也可以是无穷大),问当L非常大的时候,S的量级是L的几次方。当然,有可能S不能用L的几次方表示,那么输出-1。数据满足n<=50。

通过题面来看,就感觉这题很厉害。。。

我们先从一个环来考虑,一个环的长度为L的路径显然只有有数条,那么这个时候S就是L的一次方量级。

然后我们来考虑一个强联通分量,如果这个强联通分量不仅仅只是一个环,那么路径条数就是指数级别的了。

回到原题,我们把原图中的强联通分量全部求出来,

至少图变成了一个DAG,然后发现所有的SCC必须是环,

然后差不多dp之类的都可以做了。

由于这道题n<=50,所以根本不需要什么Tarjan,直接floyed就行了。

时间复杂度O(n^3),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxn 57
 3 using namespace std;
 4 bool vis[Maxn][Maxn];
 5 int fa[Maxn],sum[Maxn],sumedge[Maxn];
 6 int r[Maxn],f[Maxn];
 7 int n;
 8 class BigO
 9 {
10     public:
11     int minK(vector <string> graph)
12     {
13         n=graph.size();
14         for (int i=0;i<n;i++)
15             for (int j=0;j<n;j++)
16                 if (graph[i][j]==Y) vis[i][j]=true; else vis[i][j]=false;
17         for (int i=0;i<n;i++)
18             vis[i][i]=true;
19         for (int k=0;k<n;k++)
20             for (int i=0;i<n;i++)
21                 for (int j=0;j<n;j++)
22                     if (vis[i][k]&&vis[k][j]) vis[i][j]=true;
23         memset(sum,0,sizeof(sum));
24         for (int i=0;i<n;i++)
25             for (int j=0;j<n;j++)
26                 if (vis[i][j]&&vis[j][i])
27                 {
28                     fa[i]=j;
29                     ++sum[j];
30                     break;
31                 }
32         memset(sumedge,0,sizeof(sumedge));
33         for (int i=0;i<n;i++)
34             for (int j=0;j<n;j++)
35                 if (graph[i][j]==Y&&fa[i]==fa[j]&&i!=j)
36                     ++sumedge[fa[i]];
37         memset(r,0,sizeof(r));
38         memset(f,0,sizeof(f));
39         for (int i=0;i<n;i++)
40         {
41 //the SCC is more than a circle
42             if (sumedge[i]>sum[i]) return -1;
43 //the SCC is more than a point
44             if (sumedge[i]!=0) r[i]=1;
45             f[i]=r[i];
46         }
47         for (int T=0;T<n;T++)
48             for (int i=0;i<n;i++)
49                 for (int j=0;j<n;j++)
50                     if (fa[i]!=fa[j]&&graph[i][j]==Y)
51                         f[fa[j]]=max(f[fa[j]],f[fa[i]]+r[fa[j]]);
52         int res=0;
53         for (int i=0;i<n;i++)
54             res=max(f[i]-1,res);
55         return res;
56     }
57 };

Hard(900pts):

题目大意:有一个机器人在x轴上,初始位置为0,它接受到了一系列指令,每次向左一个单位或者向右一个单位。如果现在在左边界上,那么就不能再往左了,向左的指令会被忽略;如果现在在右边界上,那么就不能再往右了,向右的指令会被忽略。现在对于minA<=A<=maxA,minB<=B<=maxB,求出以A为左边界,B为右边界的最终位置的总和,数据满足所有数<=5000。

这题是个神结论题,不打算多说。。。

我们假设边界都是无穷大的时候,求出出现过的最左侧位置和最右侧位置。

如果A和B分别大于等于两边边界,那么答案就是最终位置。

如果不是的话,有一个结论就是(a,b)等于(a-1,b+1)-1,然后按照差暴力就可以了。

时间复杂度O(nX+X^2),代码如下:

 1 #include <bits/stdc++.h>
 2 #define Maxa 5007
 3 using namespace std;
 4 int ans[Maxa][Maxa];
 5 string s;
 6 long long res=0;
 7 class OneDimensionalRobot
 8 {
 9     public:
10     long long theSum(vector <string> commands1, vector <string> commands2, int minA, int maxA, int minB, int maxB)
11     {
12         s.clear();
13         for (int i=0;i<commands1.size();i++) s+=commands1[i];
14         for (int i=0;i<commands2.size();i++) s+=commands2[i];
15         int left=0,right=0,pos=0;
16         for (int i=0;i<s.length();i++)
17         {
18             if (s[i]==R) ++pos; else --pos;
19             if (-pos>left) left=-pos;
20             if (pos>right) right=pos;
21         }
22         memset(ans,0,sizeof(ans));
23         for (int i=minA;i<=maxA;i++)
24             for (int j=minB;j<=maxB;j++)
25             {
26                 if (i>=left&&j>=right) ans[i][j]=pos; else
27                 if (i==minA||j==maxB)
28                 {
29                     int now=0;
30                     for (int k=0;k<s.length();k++)
31                     {
32                         if (s[k]==R) ++now; else --now;
33                         if (-now>i) now=-i;
34                         if (now>j) now=j;
35                     }
36                     ans[i][j]=now;
37                 } else
38                 {
39                     ans[i][j]=ans[i-1][j+1];
40                     if (left>i-1||right>j) --ans[i][j];
41                 }
42             }
43         for (int i=minA;i<=maxA;i++)
44             for (int j=minB;j<=maxB;j++)
45                 res+=ans[i][j];
46         return res;
47     }
48 };

 

Topcoder SRM 608 div1 题解