打卡~

Easy(250pts):

题目大意:rating2200及以上和2200以下的颜色是不一样的(我就是属于那个颜色比较菜的),有个人初始rating为X,然后每一场比赛他的rating如果增加就会加D[i],如果减就会减D[i],但是如果rating小于0了就变成0,这个人不太喜欢比较厉害的颜色,所以他不能连续两次rating大于等于2200,求颜色变化的最多个数,保证比赛最多50场,D[i]<=10^9。

这套题还是很难的,所以我们来好好分析。

首先,样例0告诉我们贪心什么都是假的,不存在的,所以只能DP咯。

我们考虑f[i][j]表示第i场比赛打完rating是j的颜色变化最大值,

如果掉rating,那么最优值就是f[i+1][max(j-D[i],0)],

如果涨rating,又没涨到2200,那么最优值就是f[i+1][j+D[i]],

如果涨rating而且涨到2200,那么如果这是最后一场比赛直接返回1,不然就一定要求j+D[i]-D[i+1]<2200,于是最优值就是f[i+2][j+D[i]-D[i+1]]+2,

这样就能DP了,然而D[i]的范围太大了,显然会爆炸。

我们考虑如何减少状态数,于是我们发现当rating高于2200的时候,下一场必须跌而且必须跌到2200以下,

所以其实如果rating大于2200,那么我们根本不用关心他的rating是多少,

这样就可以省好多好多状态啦,然后直接dp就好了。

时间复杂度O(n*w),代码如下:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int n;
  4. int f[][];
  5. class TypoCoderDiv1
  6. {
  7. public:
  8. int getmax(vector <int> D, int X)
  9. {
  10. n=D.size();
  11. memset(f,,sizeof(f));
  12. for (int i=n-;i>=;i--)
  13. for (int j=;j<;j++)
  14. {
  15. if (j+D[i]<) f[i][j]=f[i+][j+D[i]]; else
  16. if (i+==n) f[i][j]=; else
  17. if (j+D[i]-D[i+]<) f[i][j]=f[i+][max(,j+D[i]-D[i+])]+;
  18. f[i][j]=max(f[i][j],f[i+][max(,j-D[i])]);
  19. }
  20. return f[][X];
  21. }
  22. };

Medium(550pts):

题目大意:有2N个长方形,每个长方形的长和宽都给定,现在要使得这些长方形恰好分成两组,每组N个长方形,把一组堆在桌上,最大重合面积分别为S1,S2,要求输出S1+S2的最大值,数据满足N<=100000,长宽都在10^9范围内。

种子要先预处理出来,这个没有异议的吧。。。

我们先考虑一个比较简化的问题,我们不考虑长方形的分组,只考虑N个长方形怎么叠在一起S最大。

显然我们需要把这N个长方形按照一个边角对齐,然而只看出这一个性质的话只能过div2的medium,

我们还需要看出,对于每个长方形一定是每个长方形较短的边堆放在一个方向,较长的边堆放在另一个方向,我们来证明一下。

假设两个长方形,第一个为x*y(x<=y),第二个为z*w(z<=w),并且有x<=z,

如果较短的边都在一个方向,那么S=min(x,z)*min(y,w)=x*min(y,w),

如果较短的边不在一个方向,那么S=min(x,w)*min(y,z)=x*min(y,z),

显然有min(y,w)>=min(y,z),

所以这个结论是正确的~~~

接下来,我们来考虑如何分组,

通过上面两个式子会发现,不管怎么分组,最短的那条x边一定会成为某个S的一条边,

于是我们先令所有长方形的x<=y,然后将所有长方形按照x从小到大排序,

那么x[1]一定会被选中,我们假设另一个会被选中的x边为x[i],

我们先枚举i,那么显然1~i-1都被分在了一组,还剩下i+1~2*N没有被分组,一共2*N-i个长方形。

这2*N-i个长方形中y最小的那个长方形的y值设为y0,于是y0要么和x[1]一组,要么和x[i]一组,

由于我们要求S的和最大,那么剩下的一个y显然要取那2*N-i个长方形中y值最大的那个y值。

于是经过n次的枚举,我们得到了最后的答案。

由于n<=100000,直接O(n^2)暴力显然不行(听官方题解说暴力是O(n^2logn)),所以我们需要一个随便什么数据结构来维护一下就可以了。

当然最简单的方法就是直接上两个multiset就完事啦~

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

  1. #include <bits/stdc++.h>
  2. #define Maxn 200007
  3. #define inf 10000000007
  4. using namespace std;
  5. int n;
  6. long long x[Maxn],y[Maxn];
  7. pair<long long,long long> a[Maxn];
  8. multiset<long long> st1,st2;
  9. multiset<long long>::iterator it;
  10. class PilingRectsDiv1
  11. {
  12. public:
  13. long long getmax(int N, vector <int> XS, vector <int> YS, int XA, int XB, int XC, int YA, int YB, int YC)
  14. {
  15. n=N;
  16. for (int i=;i<XS.size();i++) x[i]=XS[i],y[i]=YS[i];
  17. for (int i=XS.size();i<*n;i++) x[i]=(1LL*x[i-]*XA+XB)%XC+,y[i]=(1LL*y[i-]*YA+YB)%YC+;
  18. for (int i=;i<=*n;i++) a[i]=make_pair(min(x[i-],y[i-]),max(x[i-],y[i-]));
  19. sort(a+,a+*n+);
  20. //a[1].x must be chosen
  21. st1.clear(),st2.clear();
  22. for (int i=;i<=n;i++) st1.insert(a[i].second),st2.insert(a[i+n].second);
  23. long long ans=;
  24. for (int i=n;i;i--)
  25. {
  26. //there will be only n kind of plans
  27. //i means that the ith block has the smallest x
  28. ans=max(ans,1LL*a[].first*(*st1.begin())+1LL*a[i+].first*(*st2.begin()));
  29. st1.erase(st1.find(a[i].second)),st2.insert(a[i].second);
  30. st1.insert(*st2.begin()),st2.erase(st2.begin());
  31. }
  32. st1.clear(),st2.clear();
  33. for (int i=;i<=n;i++) st1.insert(a[i].second),st2.insert(a[i+n].second);
  34. for (int i=n;i;i--)
  35. {
  36. ans=max(ans,1LL*a[].first*(*st1.begin())+1LL*a[i+].first*(*st2.begin()));
  37. st1.erase(st1.find(a[i].second)),st2.insert(a[i].second);
  38. it=st2.end();--it;
  39. st1.insert(*it),st2.erase(it);
  40. }
  41. return ans;
  42. }
  43. };

Hard(1000pts):

这应该是我做到的SRM里面第一个分值1000分的hard题,好神哪>_<

这个题是一个超级帅无敌的公式题,但是似乎官方题解中并没有把推导过程写清楚。

题目大意:有一个N*M的方格组成的小黑盒,每个黑盒中的格子都是一块倾斜45度的玻璃板(有两个方向),现在从外围2(N+M)个格子打入激光,激光一定会退出小黑盒,这样我们得到了2(N+M)个格子和它们对应的出口。现在从小黑盒中任意去掉一块玻璃板,从外围2(N+M)个格子打入激光,发现它们对应的出口完全没有变化。求满足题意的玻璃板构成的方案数。数据满足1<=N,M<=200。

考虑对于每一块玻璃的每一个面,如果它被同一道激光照射了两次,那么说明激光形成了一个圈,由光路可逆,这光线就出不来了。。。

所以每一面最多被照射过一次,所以每一块玻璃被照射过了0次或者1次或者2次。

我们定义如果有一部分玻璃形成了一块封闭区域,而且光线如果在里面会形成循环,那么定义这一组玻璃为一个圈,

如果某一块玻璃板旋转90度后能组成一个圈,那么定义这组玻璃是一个半圈。

如果一块玻璃板被照射过了0次,直接拿走它显然不会造成任何问题,所以我们把它拿(chi)走(diao)。

如果一块玻璃板被照射了1次,我们假设光线从上射入,从左反射出。

那么我们将这块玻璃拿走,光线穿过方格到下方,通过一系列变化来到右方,从右往左穿方格。

也就是说,这块玻璃在一个圈中。

如果一块玻璃被照射了2次,我们假设光线从上射入,从左反射出,再到下方,从下进入,从右反射出。

我们将这块玻璃拿走,光线从上射入,从下穿过,再来到左方,从右侧穿过。

也就是说,如果把这块玻璃旋转90度,那么它在一个圈中,换句话说这块玻璃在一个半圈中。

问题转化为了,有多少方案使得图中存在圈或者半圈。

随手画几个圈和半圈就能够发现,一个图中如果有圈,就一定存在样例0中的5个基本图形。

问题转化为了,有多少方案使得图中至少存在5个基本图形之一。

到这里官方题解写了这么一句话:“The approach here is to do further analysis and find the following formula”,然后给出了一个公式。。。

这个公式反正我是不会证明的,也许找规律能找出来吧。。。

matthew99a对这个化简的问题使用了dp,但是我也没看懂,所以这里直接给出公式。(详见代码)

时间复杂度写什么啊。。。O(log(N*M))/O(N*M),代码如下:

  1. #include <bits/stdc++.h>
  2. #define modp 1000000007
  3. #define Maxn
  4. using namespace std;
  5. int power[];
  6. class BlackBoxDiv1
  7. {
  8. public:
  9. int count(int N, int M)
  10. {
  11. power[]=;
  12. for (int i=;i<=M*N;i++) power[i]=(2LL*power[i-])%modp;
  13. long long ans=power[N*M]-1LL*power[N]*M*M%modp-1LL*power[M]*N*N%modp+modp+modp;
  14. ans=(ans+1LL*(N-)*(N-)*(M-)*(M-)/%modp+2LL*N*M*(N+M)%modp-5LL*N*M%modp+*N+*M-+modp+modp+modp)%modp;
  15. return ans;
  16. }
  17. };

Topcoder SRM 602 div1题解的更多相关文章

  1. Topcoder SRM 607 div1题解

    好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数 ...

  2. Topcoder SRM 608 div1 题解

    Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需 ...

  3. Topcoder SRM 606 div1题解

    打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...

  4. Topcoder SRM 605 div1 题解

    日常打卡- Easy(250pts): 题目大意:你有n种汉堡包(统统吃掉-),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的 ...

  5. Topcoder SRM 604 div1题解

    CTSC考完跑了过来日常TC--- Easy(250pts): 题目大意:有个机器人,一开始的位置在(0,0),第k个回合可以向四个方向移动3^k的距离(不能不动),问是否可以到达(x,y),数据满足 ...

  6. Topcoder SRM 603 div1题解

    昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...

  7. Topcoder SRM 601 div1题解

    日常TC计划- Easy(250pts): 题目大意:有n个篮子,每个篮子有若干个苹果和橘子,先任取一个正整数x,然后从每个篮子中选出x个水果,把nx个水果放在一起,输出一共有多少种不同的组成方案.其 ...

  8. Topcoder SRM 600 div1题解

    日常TC计划正式启动! Easy(250pts): 题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数.问至少删去多少个数,使得你永远无法 ...

  9. Topcoder SRM 643 Div1 250<peter_pan>

    Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*... ...

随机推荐

  1. 根据html页面模板动态生成html页面(c#类)

    本文转载自:http://www.cnblogs.com/yuanbao/archive/2008/01/06/1027985.html点击打开链接 一直以为动态生成静态页面不好做,昨天在网上找了下, ...

  2. vim编辑器使用习惯问题

    Ubuntu中vi在编辑状态下方向键不能用,一按方向键盘就出ABCD,想插入个字母还非常麻烦,还有回格键不能删除等我们平时习惯的一些键都不能使用. 解决办法: 可以安装vim full版本,在full ...

  3. IAR 编译时找不到头文件的解决方法

    Fatal Error[Pe1696]: cannot open source file "x.h" 那是因为头文件路径没有找对 到报错的.c源文件 选中右键 选择options ...

  4. [BZOJ2527] [Poi2011]Meteors(整体二分)

    对于单个国家,可以对答案进行二分,每次找出此时的陨石数量,如果大于需要的那么答案就在[l,mid],否则就在[mid+1,r]里面 而对于很多国家,也可以进行二分,solve(l,r,L,R)表示询问 ...

  5. python基础之继承实现原理、子类调用父类的方法、封装

    继承实现原理 python中的类可以同时继承多个父类,继承的顺序有两种:深度优先和广度优先. 一般来讲,经典类在多继承的情况下会按照深度优先的方式查找,新式类会按照广度优先的方式查找 示例解析: 没有 ...

  6. 20145202马超 《Java程序设计》第三周学习总结

    ************************http://git.oschina.net/tuolemi/java这是git的那个网址********************* 函数的重载:在同一 ...

  7. 解决 ld: library not found for -lPods的问题

    现在打开有pods建好的workspace文件,尝试编译,会报ld: library not found for -lPods错误,原因就是工程里面的设置项覆盖了pods中xcconfig中的设置.解 ...

  8. React + webpack 快速搭建开发环境

    因网上大多React + webpack快速搭建的运行不起来,便自行写了一个.在搭建开发环境的前需安装nodejs,npm. 新建一个工作目录,比如叫reactdome,在reactdome目录中运行 ...

  9. 剑指Offer - 九度1507 - 不用加减乘除做加法

    剑指Offer - 九度1507 - 不用加减乘除做加法2013-11-29 20:00 题目描述: 写一个函数,求两个整数之和,要求在函数体内不得使用+.-.*./四则运算符号. 输入: 输入可能包 ...

  10. 【Python】Python PYQT4 GUI编程与exe打包

    本篇文章承接http://www.cnblogs.com/zhang-zhi/p/7646923.html#3807385,上篇文章描述了对文本文件的简单处理,本章节结合PYQT4实现该功能的GUI图 ...