Topcoder SRM 601 div1题解
日常TC计划~
Easy(250pts):
题目大意:有n个篮子,每个篮子有若干个苹果和橘子,先任取一个正整数x,然后从每个篮子中选出x个水果,把nx个水果放在一起,输出一共有多少种不同的组成方案。其中n<=50,每个篮子中每种水果的个数<=1000000,可能有篮子不存在水果。
首先考虑x的大小,由于每个篮子中都要取出x个水果,那么apple[i]+orange[i]>=x,于是我们先将所有的篮子扫一遍,得到x的上届。
接下来我们枚举x,考虑每一个篮子中的情况,
由于最后要求的是方案数,所以我们只需要关心从每个篮子取出多少个苹果和多少个橘子就可以了。
考虑第i个篮子,那么从这个篮子中最多取出min(apple[i],x)个苹果,最少取出x-min(orange[i],x)个苹果。(因为最多取出min(orange[i],x)个橘子)
于是我们将上届与下届的差全部加在一起,然后直接统计答案就可以了。
时间复杂度O(n*w),代码如下:
- #include <bits/stdc++.h>
- using namespace std;
- class WinterAndPresents
- {
- public:
- long long getNumber(vector<int> apple,vector<int> orange)
- {
- int n=apple.size();
- int mn=;
- for (int i=;i<n;i++) mn=min(mn,apple[i]+orange[i]);
- long long ans=;
- for (int k=;k<=mn;k++)
- {
- int cnt1=,cnt2=;
- //cnt1 means the least of apples should be taken
- //cnt2 means the most of apples should be taken
- for (int i=;i<n;i++)
- {
- cnt1+=k-min(k,orange[i]);
- cnt2+=min(k,apple[i]);
- }
- ans+=cnt2-cnt1+;
- }
- return ans;
- }
- };
Medium(500pts):
题目大意:给定两个正整数N,M,现在有两个集合{1,2...N}{1,2...M},对于这两个集合分别选择一个子集(可以为空),使得这两个子集没有交集并且前一个子集所有数XOR的值小于后一个子集所有数XOR的值,其中N,M<=2000。
一眼就知道这应该是一个数位DP吧~~~
我们考虑f[i][j][k]表示当前考虑是否选择数字i,前一个子集的xor值为j,后一个子集的xor值为k,
于是我们得到f[i][j][k]=f[i+1][j^i][k]+f[i+1][j][k^i]+f[i+1][j][k],
这样做的话时间复杂度O(n^3),然而n范围有2000,显然会超时。
我们考虑两个数X和Y,如果X小于Y,那么X一定在某一个二进制位小于Y,而之前几位全部相同。
于是我们发现X XOR Y前几位都是0,某一位为1,
这样我们只需要统计一下X哪一个二进制位比Y小,然后在转移的时候纪录一下A的那一个二进制位就可以了。
设f[i][j][k]表示当前考虑是否选择数字i,目前两个子集的XOR值为j,第一个子集的第i为为k。
于是我们得到f[i][j][k]=f[i+1][j][k]+f[i+1][j^(i>>pos)][k^((i>>pos)&1)]+f[i+1][j^(i>>pos)][k],
时间复杂度O(n^2logn),
感觉时间限制还是很紧,可以选择记忆化搜索,听说是严格O(n^2)的然而我不会证明。
代码如下:
- #include <bits/stdc++.h>
- #define modp 1000000007
- #define Maxn 2057
- int f[Maxn][Maxn][];
- bool flag[Maxn][Maxn][];
- using namespace std;
- int n,m;
- class WinterAndSnowmen
- {
- int tryit(int pos,int Min_num,int now1,int now2)
- {
- //Min_num means the min number you can choose
- //now1 means the xor of the numbers in the set A xor with the xor of the numbers in the set B
- //now2 means the ith position of the xor of the numbers in the set A
- //pos means i
- if (flag[Min_num][now1][now2]) return f[Min_num][now1][now2];
- flag[Min_num][now1][now2]=true;
- if (Min_num==)
- {
- if (now1==&&now2==) f[Min_num][now1][now2]=; else f[Min_num][now1][now2]=;
- return f[Min_num][now1][now2];
- }
- f[Min_num][now1][now2]=tryit(pos,Min_num-,now1,now2);
- if (Min_num<=n) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-,now1^(Min_num>>pos),now2^((Min_num>>pos)%==)))%modp;
- if (Min_num<=m) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-,now1^(Min_num>>pos),now2))%modp;
- return f[Min_num][now1][now2];
- }
- public:
- int getNumber (int N,int M)
- {
- n=N,m=M;
- int ans=;
- for (int i=;i<=;i++)
- {
- memset(f,,sizeof(f));
- memset(flag,false,sizeof(flag));
- ans=(ans+tryit(i,max(n,m),,))%modp;
- }
- return ans;
- }
- };
Hard(950pts):
题目大意:给你n个商店信息,每个店告诉你开门时间,红绿蓝的小球个数,每个商店每天只能卖一个小球,数据爆炸同一天最多只有两个商店开门,如果有两个商店,那么这两个商店必须卖同样颜色的小球,求总的方案数。其中n<=50,一个点一种颜色的小球<=100,任何的时间<=500。
也挺显然的是一道DP吧~~~
我们考虑f[i][x1][x2][y1][y2]分别表示出时间i的时候两个商店的红绿小球个数分别为x1,x2,y1,y2,
于是我们可以得出两个商店的蓝球个数,
这样就可以直接大力转移了,
时间复杂度O(T*w^4),怎么算都超时吧。。。
我们来考虑如何用更少的数字来描述一个状态,从题目中我们可以发现一个性质,每一个商店开店的时间一定是连续的一段。
我们可以继续考虑记忆化搜索,我们用三个数字来表示一个状态f[i][x1][x2],
其中i表示时间,x1表示当前的商店红球被删除的个数,x2表示当前的商店绿球被删除的个数。
我们来考虑一下对于当前的商店的定义,
如果当前的时刻t,没有商店开门,那么当前商店定义为空,x1和x2都是0。(其实好像定义成多少都没关系)
如果当前的时刻t,恰好有一个商店开门,那么当前的商店定义为这个商店。
如果当前的时刻t,恰好有两个商店开门,那么定义当前的商店为开门较早的那个商店。
于是我们来考虑一下这个函数,我们写成记忆化搜索的形式,
如果当前没有商店开门,直接将时间从t跳到t+1,将x1和x2变成0;
如果当前恰好有一个商店开门,直接将时间从t跳到当前的商店关门的时间,将x1和x2变成0;
如果当前恰好有两个商店开门,
(1)如果当前的两个商店同时关门,那么这两个商店剩余的红绿蓝球个数应该完全一致,直接乘上三者的组合数,然后将时间跳到当前商店关门时间,将x1和x2变成0;
(2)如果当前的两个商店,开门较早的关门较早,那么开门较早的商店剩余的红蓝绿球个数应该完全小于等于另一个商店的个数,直接乘上三者的组合数,然后将时间跳到当前商店关门时间,并且将当前的商店改变成另一个商店,并将x1和x2变成另一个商店的数据;
(3)如果当前的两个商店,开门较早的关门较晚,那么另一个商店的红蓝绿球个数完全小于等于当前商店剩下来的个数,那么直接处理掉另一个商店,乘上三者的组合数,把时间跳到另一个商店的关门时间,处理x1和x2。(分别减掉另一个商店的个数就可以了)
最后来考虑三者的组合数,我们有a个红球,b个蓝球,c个绿球,不同的排列方式一共有C(a+b+c,a)*C(b+c,b),
于是我们可以先预处理出C数组和时间轴,然后dp记忆化搜索就可以了。
时间复杂度O(Tm^2),代码如下:
- #include <bits/stdc++.h>
- #define Maxn 57
- #define Maxa 107
- #define Maxt 507
- #define modp 1000000007
- using namespace std;
- struct data {int l,r,x,y,z;} a[Maxn];
- int cover[Maxt][],combination[*Maxa+][*Maxa+];
- int f[Maxt+][Maxa][Maxa];
- bool flag[Maxt][Maxa][Maxa];
- //cover is the data of the two shops in the same day
- int n;
- class WinterAndShopping
- {
- int calc(int x,int y,int z)
- {
- int ans=(1LL*combination[x+y+z][x]*combination[y+z][y])%modp;
- return ans;
- }
- int tryit(int t,int x,int y)
- {
- //t means the present time
- //x means how many red balls have been taken from the shop
- //y means how many green balls have been taken from the shop
- //if there is only one shop
- //we can calculate how many blue balls
- //if there is two shops at the same time
- //we can also calculate it and skip the time to the next shop
- if (flag[t][x][y]) return f[t][x][y];
- flag[t][x][y]=true;
- int p=cover[t][],q=cover[t][];
- if (p<)
- {
- //there is no shop open at the moment
- f[t][x][y]=tryit(t+,,);
- return f[t][x][y];
- }
- int x1=a[p].x-x,y1=a[p].y-y,z1=a[p].z-t+a[p].l+x+y;
- //x1 means how many red balls there are in the first shop
- //y1 means how many green balls there are in the first shop
- //z1 means how many blue balls there are in the first shop
- if (q<)
- {
- //there is exactly one shop open at the moment
- if (t==a[p].r)
- {
- //we should skip the time directly to the next shop
- f[t][x][y]=tryit(t+,,);
- return f[t][x][y];
- } else
- {
- if (x1) f[t][x][y]=tryit(t+,x+,y);
- if (y1) f[t][x][y]=(f[t][x][y]+tryit(t+,x,y+))%modp;
- if (z1) f[t][x][y]=(f[t][x][y]+tryit(t+,x,y))%modp;
- return f[t][x][y];
- }
- }
- //there is exactly two shops open at the moment
- if (a[p].r==a[q].r)
- {
- //the two shops will be closed at the same time
- //then the three kinds of balls should be the same
- if (x1==a[q].x&&y1==a[q].y&&z1==a[q].z)
- {
- f[t][x][y]=(1LL*tryit(a[p].r+,,)*calc(x1,y1,z1))%modp;
- }
- return f[t][x][y];
- } else if (a[p].r<a[q].r)
- {
- //the first shop will be closed earlier than the second one
- //then the three kinds of balls in the first shop should not be more then the second one
- if (x1<=a[q].x&&y1<=a[q].y&&z1<=a[q].z)
- {
- f[t][x][y]=(1LL*tryit(a[p].r+,x1,y1)*calc(x1,y1,z1))%modp;
- }
- return f[t][x][y];
- } else if (a[p].r>a[q].r)
- {
- //the first shop will be closed later than the second one
- //then the three kinds of balls i the first shop should not be less than the second one
- if (x1>=a[q].x&&y1>=a[q].y&&z1>=a[q].z)
- {
- f[t][x][y]=(1LL*tryit(a[q].r+,x+a[q].x,y+a[q].y)*calc(a[q].x,a[q].y,a[q].z))%modp;
- }
- return f[t][x][y];
- }
- }
- public:
- int getNumber(vector<int> first, vector <int> red, vector <int> green, vector <int> blue)
- {
- n=first.size();
- //deal with the data of the combination number
- memset(combination,,sizeof(combination));
- combination[][]=;
- for (int i=;i<=*Maxa;i++)
- {
- combination[i][]=;
- for (int j=;j<=i;j++)
- combination[i][j]=(combination[i-][j]+combination[i-][j-])%modp;
- }
- //deal with the data of the time schedule
- for (int i=;i<Maxt;i++) cover[i][]=cover[i][]=-;
- for (int i=;i<n;i++)
- {
- a[i].l=first[i],a[i].x=red[i],a[i].y=green[i],a[i].z=blue[i];
- a[i].r=a[i].l+a[i].x+a[i].y+a[i].z-;
- for (int j=a[i].l;j<=a[i].r;j++)
- {
- if (cover[j][]==-) cover[j][]=i; else
- {
- cover[j][]=i;
- if (a[i].l<a[cover[j][]].l) swap(cover[j][],cover[j][]);
- }
- }
- }
- memset(f,,sizeof(f));
- memset(flag,false,sizeof(flag));
- f[Maxt][][]=,flag[Maxt][][]=true;
- return tryit(,,);
- }
- };
打卡完成!
Topcoder SRM 601 div1题解的更多相关文章
- Topcoder SRM 602 div1题解
打卡- Easy(250pts): 题目大意:rating2200及以上和2200以下的颜色是不一样的(我就是属于那个颜色比较菜的),有个人初始rating为X,然后每一场比赛他的rating如果增加 ...
- Topcoder SRM 607 div1题解
好久没来写了,继续继续... Easy(250pts): //前方请注意,样例中带有zyz,高能预警... 题目大意:给你一个字符串,中间有一些是未知字符,请你求出这个字符串的回文子串个数的期望值.数 ...
- Topcoder SRM 608 div1 题解
Easy(300pts): 题目大意:有n个盒子,一共有S个苹果,每个盒子有多少个苹果不知道,但是知道每个盒子的苹果下限和上限.现在要至少选择X个苹果,问如果要保证无论如何都能获得至少X个苹果,至少需 ...
- Topcoder SRM 606 div1题解
打卡! Easy(250pts): 题目大意:一个人心中想了一个数,另一个人进行了n次猜测,每一次第一个人都会告诉他实际的数和猜测的数的差的绝对值是多少,现在告诉你所有的猜测和所有的差,要求你判断心中 ...
- Topcoder SRM 605 div1 题解
日常打卡- Easy(250pts): 题目大意:你有n种汉堡包(统统吃掉-),每一种汉堡包有一个type值和一个taste值,你现在要吃掉若干个汉堡包,使得它们taste的总和*(不同的type值的 ...
- Topcoder SRM 604 div1题解
CTSC考完跑了过来日常TC--- Easy(250pts): 题目大意:有个机器人,一开始的位置在(0,0),第k个回合可以向四个方向移动3^k的距离(不能不动),问是否可以到达(x,y),数据满足 ...
- Topcoder SRM 603 div1题解
昨天刚打了一场codeforces...困死了...不过赶在睡前终于做完了- 话说这好像是我第一次做250-500-1000的标配耶--- Easy(250pts): 题目大意:有一棵树,一共n个节点 ...
- Topcoder SRM 600 div1题解
日常TC计划正式启动! Easy(250pts): 题目大意:给你一个集合,里面一堆数,初始数为0,给你一个目标数,你可以选择集合中若干个数进行OR操作来得到目标数.问至少删去多少个数,使得你永远无法 ...
- Topcoder SRM 643 Div1 250<peter_pan>
Topcoder SRM 643 Div1 250 Problem 给一个整数N,再给一个vector<long long>v; N可以表示成若干个素数的乘积,N=p0*p1*p2*... ...
随机推荐
- 根据html页面模板动态生成html页面(c#类)
本文转载自:http://www.cnblogs.com/yuanbao/archive/2008/01/06/1027985.html点击打开链接 一直以为动态生成静态页面不好做,昨天在网上找了下, ...
- python__基础 : 类属性,类方法,静态方法
类属性 定义在类里面,方法外面的属性,一般属于这个类,如下面的 num 就是类属性: class Test: num = 类属性用 实例.类属性 或者 类.类属性 都可以访问, 如 a = Te ...
- 477. Total Hamming Distance
class Solution { public: int totalHammingDistance(vector<int>& nums) { ; ; i < ; i++) { ...
- Reward HDU - 2647
传送门 Dandelion's uncle is a boss of a factory. As the spring festival is coming , he wants to dis ...
- 【UE4】二十三、UE4笔试面试题
在CSDN博客看到的,带着这些问题,多多留意,正所谓带着问题学习. 一. 1.Actor的EndPlay事件在哪些时候会调用? 2.BlueprintImplementableEvent和Bluepr ...
- 2 semantic ui 框架的应用
为什么使用css框架 1.使用基础样式 : ui segment 分段:内容片段 <link rel="stylesheet" href="css/semanti ...
- Quartus 11进行编译Compile Design的时候出现错误near text ã
1. 设计的工程在Compile Design的时候出现以下的错误,百思不得姐 Error (): Verilog HDL syntax error at div_5.v() near text ã ...
- gulp相关
'use strict'; var gulp = require('gulp'), webserver = require('gulp-webserver'), //gulp服务器 connect = ...
- Linux认知之旅【01 与Linux第一次亲密接触】!
一.搜索LINUX,了解它的前世今生! linux很厉害,应用在很多方面,我知道有超算.IOT.树莓派. 而且好多开发人员都在用这个系统.linux作为服务器使用,常年不用重启,不宕机,很少受病毒影响 ...
- Entity Framework(三)---FluentAPI和增删查改
一.FluentAPI: 1.基本配置: namespace ConsoleApp14.ModelConfig { public class PersonConfig: EntityTypeConfi ...