日常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),代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 class WinterAndPresents
 4 {
 5     public:
 6     long long getNumber(vector<int> apple,vector<int> orange)
 7     {
 8         int n=apple.size();
 9         int mn=2000000;
10         for (int i=0;i<n;i++) mn=min(mn,apple[i]+orange[i]);
11         long long ans=0;
12         for (int k=1;k<=mn;k++)
13         {
14             int cnt1=0,cnt2=0;
15 //cnt1 means the least of apples should be taken
16 //cnt2 means the most of apples should be taken
17             for (int i=0;i<n;i++)
18             {
19                 cnt1+=k-min(k,orange[i]);
20                 cnt2+=min(k,apple[i]);
21             }
22             ans+=cnt2-cnt1+1;
23         }
24         return ans;
25     }
26 };

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)的然而我不会证明。

代码如下:

 1 #include <bits/stdc++.h>
 2 #define modp 1000000007
 3 #define Maxn 2057
 4 int f[Maxn][Maxn][2];
 5 bool flag[Maxn][Maxn][2];
 6 using namespace std;
 7 int n,m;
 8 class WinterAndSnowmen
 9 {
10     int tryit(int pos,int Min_num,int now1,int now2)
11     {
12 //Min_num means the min number you can choose
13 //now1 means the xor of the numbers in the set A xor with the xor of the numbers in the set B
14 //now2 means the ith position of the xor of the numbers in the set A
15 //pos means i
16         if (flag[Min_num][now1][now2]) return f[Min_num][now1][now2];
17         flag[Min_num][now1][now2]=true;
18         if (Min_num==0)
19         {
20             if (now1==1&&now2==0) f[Min_num][now1][now2]=1; else f[Min_num][now1][now2]=0;
21             return f[Min_num][now1][now2];
22         }
23         f[Min_num][now1][now2]=tryit(pos,Min_num-1,now1,now2);
24         if (Min_num<=n) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-1,now1^(Min_num>>pos),now2^((Min_num>>pos)%2==1)))%modp;
25         if (Min_num<=m) f[Min_num][now1][now2]=(f[Min_num][now1][now2]+tryit(pos,Min_num-1,now1^(Min_num>>pos),now2))%modp;
26         return f[Min_num][now1][now2];
27     }
28     public:
29     int getNumber (int N,int M)
30     {
31         n=N,m=M;
32         int ans=0;
33         for (int i=0;i<=12;i++)
34         {
35             memset(f,0,sizeof(f));
36             memset(flag,false,sizeof(flag));
37             ans=(ans+tryit(i,max(n,m),0,0))%modp;
38         }
39         return ans;
40     }
41 };

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),代码如下:

  1 #include <bits/stdc++.h>
  2 #define Maxn 57
  3 #define Maxa 107
  4 #define Maxt 507
  5 #define modp 1000000007
  6 using namespace std;
  7 struct data {int l,r,x,y,z;} a[Maxn];
  8 int cover[Maxt][2],combination[3*Maxa+1][3*Maxa+1];
  9 int f[Maxt+1][Maxa][Maxa];
 10 bool flag[Maxt][Maxa][Maxa];
 11 //cover is the data of the two shops in the same day
 12 int n;
 13 class WinterAndShopping
 14 {
 15     int calc(int x,int y,int z)
 16     {
 17         int ans=(1LL*combination[x+y+z][x]*combination[y+z][y])%modp;
 18         return ans;
 19     }
 20     int tryit(int t,int x,int y)
 21     {
 22 //t means the present time
 23 //x means how many red balls have been taken from the shop
 24 //y means how many green balls have been taken from the shop
 25 //if there is only one shop
 26 //we can calculate how many blue balls
 27 //if there is two shops at the same time
 28 //we can also calculate it and skip the time to the next shop
 29         if (flag[t][x][y]) return f[t][x][y];
 30         flag[t][x][y]=true;
 31         int p=cover[t][0],q=cover[t][1];
 32         if (p<0)
 33         {
 34 //there is no shop open at the moment
 35             f[t][x][y]=tryit(t+1,0,0);
 36             return f[t][x][y];
 37         }
 38         int x1=a[p].x-x,y1=a[p].y-y,z1=a[p].z-t+a[p].l+x+y;
 39 //x1 means how many red balls there are in the first shop
 40 //y1 means how many green balls there are in the first shop
 41 //z1 means how many blue balls there are in the first shop
 42         if (q<0)
 43         {
 44 //there is exactly one shop open at the moment
 45             if (t==a[p].r)
 46             {
 47 //we should skip the time directly to the next shop
 48                 f[t][x][y]=tryit(t+1,0,0);
 49                 return f[t][x][y];
 50             } else
 51             {
 52                 if (x1) f[t][x][y]=tryit(t+1,x+1,y);
 53                 if (y1) f[t][x][y]=(f[t][x][y]+tryit(t+1,x,y+1))%modp;
 54                 if (z1) f[t][x][y]=(f[t][x][y]+tryit(t+1,x,y))%modp;
 55                 return f[t][x][y];
 56             }
 57         }
 58 //there is exactly two shops open at the moment
 59         if (a[p].r==a[q].r)
 60         {
 61 //the two shops will be closed at the same time
 62 //then the three kinds of balls should be the same
 63             if (x1==a[q].x&&y1==a[q].y&&z1==a[q].z)
 64             {
 65                 f[t][x][y]=(1LL*tryit(a[p].r+1,0,0)*calc(x1,y1,z1))%modp;
 66             }
 67             return f[t][x][y];
 68         } else if (a[p].r<a[q].r)
 69         {
 70 //the first shop will be closed earlier than the second one
 71 //then the three kinds of balls in the first shop should not be more then the second one
 72             if (x1<=a[q].x&&y1<=a[q].y&&z1<=a[q].z)
 73             {
 74                 f[t][x][y]=(1LL*tryit(a[p].r+1,x1,y1)*calc(x1,y1,z1))%modp;
 75             }
 76             return f[t][x][y];
 77         } else if (a[p].r>a[q].r)
 78         {
 79 //the first shop will be closed later than the second one
 80 //then the three kinds of balls i the first shop should not be less than the second one
 81             if (x1>=a[q].x&&y1>=a[q].y&&z1>=a[q].z)
 82             {
 83                 f[t][x][y]=(1LL*tryit(a[q].r+1,x+a[q].x,y+a[q].y)*calc(a[q].x,a[q].y,a[q].z))%modp;
 84             }
 85             return f[t][x][y];
 86         }
 87     }
 88     public:
 89     int getNumber(vector<int> first, vector <int> red, vector <int> green, vector <int> blue)
 90     {
 91         n=first.size();
 92 //deal with the data of the combination number
 93         memset(combination,0,sizeof(combination));
 94         combination[0][0]=1;
 95         for (int i=1;i<=3*Maxa;i++)
 96         {
 97             combination[i][0]=1;
 98             for (int j=1;j<=i;j++)
 99                 combination[i][j]=(combination[i-1][j]+combination[i-1][j-1])%modp;
100         }
101 //deal with the data of the time schedule
102         for (int i=0;i<Maxt;i++) cover[i][0]=cover[i][1]=-1;
103         for (int i=0;i<n;i++)
104         {
105             a[i].l=first[i],a[i].x=red[i],a[i].y=green[i],a[i].z=blue[i];
106             a[i].r=a[i].l+a[i].x+a[i].y+a[i].z-1;
107             for (int j=a[i].l;j<=a[i].r;j++)
108             {
109                 if (cover[j][0]==-1) cover[j][0]=i; else
110                 {
111                     cover[j][1]=i;
112                     if (a[i].l<a[cover[j][0]].l) swap(cover[j][0],cover[j][1]);
113                 }
114             }
115         }
116         memset(f,0,sizeof(f));
117         memset(flag,false,sizeof(flag));
118         f[Maxt][0][0]=1,flag[Maxt][0][0]=true;
119         return tryit(1,0,0);
120     }
121 };

打卡完成!

转载于:https://www.cnblogs.com/Tommyr7/p/6801390.html

Topcoder SRM 601 div1题解相关推荐

  1. topcoder srm 714 div1

    problem1 link 倒着想.每次添加一个右括号再添加一个左括号,直到还原.那么每次的右括号的选择范围为当前左括号后面的右括号减去后面已经使用的右括号. problem2 link 令$h(x) ...

  2. topcoder srm 691 div1 -3

    1.给定一个$n$个顶点$n$个边的图,边是$(i,a_{i})$,顶点编号$[0,n-1]$.增加一个顶点$n$,现在选出一个顶点集$M$,对于任意的在$M$中 的顶点$x$,去掉边$(x,a_{x ...

  3. topcoder srm 706 div1

    1.给定一个迷宫,点号表示不可行,井号表示可行.现在可以改变其中的一些井号的位置.问最少改变多少个井号可以使得从左上角到右下角存在路径. 思路:设高为$n$,宽为$m$,若井号的个数$S$小于$n+m ...

  4. topcoder srm 694 div1 -3

    1.给出$n$个数字,将其分成三个非空的组,每组的权值为该组所有数字的抑或.选择一种分法使得三组的权值和最大? 思路:记录前两组的权值且三组有没有数字时第三组的值.(当前两组的值知道时第三组的权值是确 ...

  5. topcoder srm 330 div1

    problem1 link 直接模拟. import java.util.*; import java.math.*; import static java.lang.Math.*;public cl ...

  6. topcoder srm 360 div1

    problem1 link (1)$n \neq m$时,假设$n<m$,那么同一行中的$m$个数字必定都相等. (2)$n=m$时,要满足任意的$i_{1},i_{2},j_{1},j_{2} ...

  7. topcoder srm 635 div1

    problem1 link 首先枚举长度$L$.然后计算每一段长度$L$的差值最大公约数,然后差值除以最大公约数的结果可以作为当前段的关键字.然后不同段就可以比较他们的关键字,一样就是可以转化的. p ...

  8. topcoder srm 495 div1

    problem1 link 从前向后确定一下,然后再从后向前确定一下.一样的话就是可以确定的. problem2 link 首先将强连通分量缩点.理论上来说,只需要遍历所有入度为0的联通块中的一个即可 ...

  9. topcoder srm 325 div1

    problem1 link $g[i]$表示解决前$i$个的代价,那么$g[i]$是所有$g[j]+cost(j+1,i)$的最小值. import java.util.*; import java. ...

  10. topcoder srm 500 div1

    problem1 link 如果decisions的大小为0,那么每一轮都是$N$个人.答案为0. 否则,如果答案不为0,那么概率最大的一定是一开始票数最多的人.因为这个人每一轮都在可以留下来的人群中 ...

最新文章

  1. Autofac3 在MVC4中的运用原理
  2. 3.2 神经网络概述-机器学习笔记-斯坦福吴恩达教授
  3. 阿里云 Serverless 再升级,从体验上拉开差距
  4. [数据结构]顺序单链表插入
  5. 昨天飞鸽传书可能是因为太累了
  6. Flutter State生命周期 Flutter Widget生命周期 Flutter 应用程序生命周期
  7. python排序方法_python内置的排序方法
  8. 2015年4月20 号的日志
  9. Redis-数据结构01-压缩列表(ziplist)
  10. python实现目录中制定内容查找
  11. win10安装ipython_win10下安装Anaconda的教程(python环境+jupyter_notebook)
  12. Sony本如何进入biso设置
  13. Java大型工程项目管理系统源码,原生APP源码,建筑工程管理源码
  14. 问题 B: 神棍的纯真愿望
  15. R语言 | 将CSV文件中原本为空白值的chr数据赋值为NA
  16. 计算机网络上有个红叉没无线,电脑连接不可用红叉,有无线网络但无法连接上wifi...
  17. 代码保护(一) 几款加壳工具
  18. sizzle.js学习笔记利用闭包模拟实现数据结构:字典(Map)
  19. 虹膜识别论文2:An Experimental Study of Deep Convolutional Features For Iris Recognition 2016年 学习心得
  20. 如何在spring事务提交成功后再进行异步操作

热门文章

  1. python 时间处理_Python如何进行时间处理
  2. docker MySQL-错误:2059-Authentication plugin ‘caching_sha2_password‘ cannot be loaded
  3. 设计模式之——抽象工厂模式
  4. oracle中树形数据,ORACLE树形数据解决方法
  5. JavaScript之调用函数的方式
  6. 【渝粤教育】国家开放大学2018年秋季 0700-22T中级会计实务(一) 参考试题
  7. 【渝粤教育】国家开放大学2018年春季 0692-21T化工设备机械基础 参考试题
  8. [渝粤教育] 西南科技大学 管理学原理 在线考试复习资料(3)
  9. Pandas系列(九)axis参数理解
  10. 求解偏微分方程开源有限元软件deal.II学习--Step 2