Topcoder SRM 608 div1 题解

Posted 一只蒟篛酱的日常~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 题解的主要内容,如果未能解决你的问题,请参考以下文章

Topcoder SRM 605 div1 题解

Topcoder SRM 603 div1题解

Topcoder SRM 604 div1题解

Topcoder SRM 607 div1题解

TopCoder SRM502 Div1 1000 动态规划

topcoder srm 335 div1