拼不出的数
lost.in/.out/.cpp
【问题描述】
3 个元素的集合{5, 1,2} 的所有子集的和分别是0,1, 2, 3, 5, 6, 7, 8。发
现最小的不能由该集合子集拼出的数字是4。
现在给你一个n 个元素的集合,问你最小的不能由该集合子集拼出的
数字是多少。
注意32 位数字表示范围。

【输入格式】
第一行一个个整数n。
第二行n 个正整数ai,表示集合内的元素。
【输出格式】
一行一个个整数答案。

【样例输入】
3
5 1 2
【样例输出】
4
【数据规模和约定】
对于30% 的数据,满足n <=15。
对于60% 的数据,满足n <= 1000。
对于100% 的数据,满足n <= 100000; 1 <= ai <= 10^9。

题解:排序+前缀和

sum表示当前前缀和

如果当前加入的数大于前缀和+1,那么输出前缀和+1,否则继续。

因为需要表示连续的整数,那么相邻的数最多只能差1.

如果排序后k前面的数字之和<k-1,那么k-1这个数就无法表示。

再详细的说就是

现在能表示出[0,0]这个区间,那么对于排序后接下来的数k,如果k>1,那么1

这个数就永远也拼不出来。那么对于之前能拼出的区间为[0,x],加上k之后能拼出

的数至少为[k,x+k],必须要求[0,x]这个区间的右端点和[k,k+x]的左端点连续才能把所有

数都拼出来,也就是k<=x+1。

代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #define LL long long
  6. using namespace std;
  7.  
  8. int n,a[];
  9. LL sum;
  10.  
  11. int main(){
  12. scanf("%d",&n);
  13. for(int i=;i<=n;i++)scanf("%d",&a[i]);
  14. sort(a+,a+n+);
  15. for(int i=;i<=n;i++){
  16. if(a[i]>sum+){
  17. printf("%lld\n",sum+);
  18. return ;
  19. }
  20. sum+=a[i];
  21. }
  22. printf("%lld\n",sum+);
  23. return ;
  24. }

AC

整除
div.in/.out/.cpp
【问题描述】

给定整数n,问[n/i],的结果有多少不同的数字。(1<=i<=n),i为正整数。

比如n=5时,[5/1]=5,[5/2]=2,[5/3]=1,[5/4]=1,[5/5]=1,所以结果共有三个

不同的数字。

注意32位整数的表示范围。

【输入格式】

一行一个整数n

【输出格式】

一行一个整数答案

【样例输入】

5

【样例输出】

3

【数据规模与约定】

对于30% 的数据,满足1 <=n <= 10^3
对于60% 的数据,满足1 <= n <= 10^12
对于100% 的数据,满足1 <= n <= 10^18

题解:

发现一段区间的数是连续的,想办法跳过去。

时间复杂度根号n 因为至多有根号n个数

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #define LL long long
  5. using namespace std;
  6.  
  7. LL n,ans;
  8.  
  9. int main(){
  10. scanf("%lld",&n);
  11. for(register LL i=;i<=n;i++){
  12. LL a=n/i;
  13. LL b=n/a;
  14. i=b;
  15. ans++;
  16. }
  17. printf("%lld",ans);
  18. return ;
  19. }

60

正解:

找规律

对于n=7

i ret

1 7

2 3

-------

3 2

...

7 1

发现在横线上方有两个答案,下方也有两个.把重复的答案去掉就成了

1 7

2 3

------

3 2

7 1

发现 1--7和7--1,2--3和3--2是对应的.相当于根号7作为一个分界线.

那么答案会是(根号n)*2么?

再看个例子9

1 9

2 4

3 3

4 2

....

9 1

答案是5,而不是sqrt(9)*2=6(这里的sqrt都是下取整).这是因为3多数了一次.

那么是不是对于完全平方数答案就要-1呢?对拍发现不是这样的.

对于10

1 10

2  5

3 3

4 2

5 2

6 1

...

10 1

发现答案是5,不是sqrt(10)*2-1.这是为什么呢?这是因为10/sqrt(10)=sqrt(3),这里的3又多数了一次.

所以对于[N/[N]]=[N],答案都要减1.就可以做到O(1)得出答案. 这是同学给我讲的好详细哒orz..

也可以打表找规律

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstdio>
  4. #define LL long long
  5. using namespace std;
  6. LL n;
  7. int main(){
  8. scanf("%lld",&n);
  9. LL k=sqrt(n),ans=k*;
  10. if(k*k<=n&&k*(k+)>n)ans--;
  11. printf("%lld\n",ans);
  12. return ;
  13. }

AC

std的做法是二分。

对于[n/i]假设它的值是

100 70 60 50 20 19 18 17 16 15 14 1 1 1 1

那么相邻两项的差值为[n/i]-[n/i-1],如果按浮点数比较,

[n/i]-[n/i-1]<=1,那么1--[n/i]这段区间的所有数都存在,

对于[n/i]和[n/i+1]的差大于1,对于不同的i存在不同的[n/i],

对于i越大,差值越小。//我也不太明白这个做法。

我又认真看了看...下面是我的理解...

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <cassert>
  5. using namespace std;
  6.  
  7. typedef long long LL;
  8. LL n;
  9. bool check(LL x){ // n <= x*(x+1)
  10. if(x*.*(x+)>1e18) return true;
  11. if(n <= x *(x+)) return true;
  12. return false;
  13. }
  14. int main(){
  15. freopen("div.in","r",stdin);
  16. freopen("div.out","w",stdout);
  17. scanf("%lld",&n);
  18. if(n==){
  19. puts("");
  20. }else if(n==){
  21. puts("");
  22. }else{
  23. LL L = ,R=n-;
  24. while(R-L>){
  25. LL mid = (L+R)/;
  26. if(check(mid)) R=mid;
  27. else L=mid;
  28. }
  29. // assert(check(R));
  30. printf("%lld\n",L+(n/R));
  31. }
  32.  
  33. return ;
  34. }

AC

钻石diamond.in/.out/.cpp

【问题描述】
你有n 个“量子态” 的盒子,每个盒子里可能是一些钱也可能是一个钻
石。
现在你知道如果打开第i 个盒子,有Pi/100 的概率能获得Vi 的钱,有

1 -Pi/100 的概率能获得一个钻石。

现在你想知道,如果恰好获得k(0<= k<= n) 个钻石,并且获得钱数大
于等于m 的概率是多少。
请你对0 <= k<= n 输出n+1 个答案。
答案四舍五入保留3 位小数。
【输入格式】
第一行两个整数n,m,见题意。
接下来n 行,每行两个整数Vi; Pi。
【输出格式】
输出共n+1 行,表示0<= k<= n 的答案。
【样例输入】
2 3
2 50
3 50
【样例输出】
0.250
0.250
0.000

题目大意:有n个盒子,打开时有pi的概率是钱,有1-pi的概率是钻石,求当

钻石的个数为0-n时并且钱的个数大于等于m时的概率

题解:

搜索60分

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #define LL long long
  5. using namespace std;
  6.  
  7. int n,m;
  8. double ans[];
  9. struct BOX{
  10. int v,p;
  11. }b[];
  12.  
  13. inline int read(){
  14. char ch=getchar();int x=,f=;
  15. for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
  16. for(;isdigit(ch);ch=getchar())x=x*+ch-'';
  17. return x*f;
  18. }
  19.  
  20. void dfs(int x,LL sumz,int sumq,double w){
  21. if(x==n+){
  22. if(sumq>=m)ans[sumz]+=w;
  23. return;
  24. }
  25. dfs(x+,sumz+,sumq,w*(1.0-b[x].p*1.0/));
  26. dfs(x+,sumz,sumq+b[x].v,w*b[x].p*1.0/);
  27. }
  28.  
  29. int main(){
  30. freopen("diamond.in","r",stdin);
  31. freopen("diamond.out","w",stdout);
  32. n=read();m=read();
  33. /*n个盒子 m钱数大于m*/
  34. for(int i=;i<=n;i++){
  35. b[i].v=read();b[i].p=read();
  36. }
  37. /*pi/100的概率获得钱*/
  38. dfs(,,,1.0);
  39. /*目前看第1个盒子,钻石数和钱数为0
  40. 当前情况出现的概率为0.0
  41. */
  42. for(int i=;i<=n;i++)
  43. printf("%.3lf\n",ans[i]);
  44. fclose(stdin);fclose(stdout);
  45. return ;
  46. }

60

正解

一直以为是dp,dp应该也可过。正解是双向搜索 meet in the middle

我们可以把盒子分成两半 1--n/2和n/2+1--n,搜索出后一半的情况,在前一半的状态中

找出两半合并后满足条件的状态,满足的条件就是钱数>=n。对于每一种状态我们可以用

一个三元组表示{a,b,c}表示状态的钻石个数为a,钱数为b,概率为c。

对于这样一组样例

2 50

3 50

--------

4 50

5 50

那么前一半的状态用三元组表示为

{0,5,0.25},{1,3,0.25},{1,2,0.25},{1,3,0.25};

好,我们知道这样表示了。代码实现的主要过程就是,我们搜索后一半的状态,

找前一半有多少符合的。

例如,现在我们已经搜出后一半的所有三元组了。

前一半的某个状态为{cnt,money,nowp},那么我们至少需要的钱就是L=m-money,

那就需要找后一半状态里钱数大于等于L的,可以二分找。对于后一半的所有状态,按钻石数分块,

意思是,钻石数为0的放在一起,为1的放在一起...,并且对于每一块做概率的前缀和。找出每一块里

钱数大于等于L的那个状态,就可以用前缀和求出钱数大于等于L状态的概率的总和tmp。那么钻石

数为p时最答案的贡献就是,在后一半找到的概率和tmp,和前一半的现在搜到的状态的概率nowp的乘积。

代码:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<vector>
  5. using namespace std;
  6. int tt;
  7. int n,m;
  8. int v[];
  9. double p[];
  10. double ans[];
  11. vector<pair<int,double> > sta[];
  12. int main(){
  13. freopen("diamond.in","r",stdin);
  14. freopen("diamond.out","w",stdout);
  15. scanf("%d%d",&n,&m);
  16. for(int i=,x;i<=n;i++){
  17. scanf("%d%d",&v[i],&x);
  18. p[i]=x/.;
  19. }
  20. for(int i=;i<=n;i++){
  21. sta[i].clear();
  22. }
  23. int an=(n/2.5)+;
  24. int bn=n-an;
  25. for(int st=;st<<<bn;st++){
  26. double nowp=;
  27. int cnt=,money=;
  28. for(int i=;i<bn;i++){
  29. if((st>>i)&){
  30. money+=v[n-i];
  31. nowp*=p[n-i];
  32. }else{
  33. cnt++;
  34. nowp*=(-p[n-i]);
  35. }
  36. }
  37. sta[cnt].push_back(make_pair(money,nowp));
  38. }
  39. for(int i=;i<=n;i++){
  40. sort(sta[i].begin(),sta[i].end());
  41. for(int j=;j<sta[i].size();j++){
  42. sta[i][j].second+=sta[i][j-].second;
  43. }
  44. }
  45. for(int st=;st<<<an;st++){
  46. double nowp=;
  47. int cnt=,money=;
  48. for(int i=;i<an;i++){
  49. if((st>>i)&){
  50. money+=v[i+];
  51. nowp*=p[i+];
  52. }else{
  53. cnt++;
  54. nowp*=(-p[i+]);
  55. }
  56. }
  57. for(int i=;i<=bn;i++){
  58. // now d =cnt+i
  59. int L = m-money;
  60. vector<pair<int,double> >::iterator it = lower_bound(sta[i].begin(),sta[i].end(),make_pair(L,-.));
  61. double tmp = sta[i].back().second;
  62. if(it!= sta[i].begin()){
  63. it--;
  64. tmp-=it->second;
  65. }
  66. ans[cnt+i] += tmp*nowp;
  67. }
  68. }
  69. for(int i=;i<=n;i++){
  70. printf("%.3f\n",ans[i]);
  71. }
  72. fclose(stdout);
  73. return ;
  74. }

AC

2017.10.5北京清北综合强化班DAY5的更多相关文章

  1. 2017.10.3北京清北综合强化班DAY3

    括号序列(bracket) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法的 ...

  2. 2017.10.4北京清北综合强化班DAY4

    财富(treasure) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...

  3. 2017.10.7北京清北综合强化班DAY7

    1.计数 (count.cpp/c/pas) 时间限制:1s 内存限制:256MB [问题描述] 给出m个数a[1],a[2],…,a[m] 求1~n中有多少数不是a[1],a[2],…,a[m]的倍 ...

  4. 2017.10.6北京清北综合强化班DAY6

    题目大意:改变一个数的位置 把一个序列变成不下降序列 题解: 设置一个pre,如果破坏单调性,就把‘删除’这个.否则把pre修改为当前元素的值. 考试时这样得了90分,是因为我的做法只能过这样的数据 ...

  5. 2017.10.1北京清北综合强化班DAY1

    a[问题描述]你是能看到第一题的 friends 呢.——hja何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx. 何大爷今天为字符串定义了新的权值计算方法.一个字符串 由小写字母组成,字符串 ...

  6. 2017.10.2北京清北综合强化班DAY2

    a[问题描述]你是能看到第一题的 friends呢.                                                —— hja世界上没有什么比卖的这 贵弹丸三还令人绝 ...

  7. 北京清北 综合强化班 Day5

    T1 思路: 输入数据,sort一下, 如果a[i]>sum+1(前缀和) 那么sum+1就一定不会被拼出来, 然后输出即可. 上代码: #include <iostream> #i ...

  8. 北京清北 综合强化班 Day4

    财富(treasure) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...

  9. 北京清北 综合强化班 Day3

    括号序列(bracket) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法的 ...

随机推荐

  1. 九度OJ 1200:最大的两个数 (最值)

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2904 解决:761 题目描述: 输入一个四行五列的矩阵,找出每列最大的两个数. 输入: 输入第一行包括一个整数n(1<=n<= ...

  2. iOS main函数讲解

    int main(int argc, char * argv[]) { @autoreleasepool { //四个参数 主要讲解后面两个参数 /* 第三个参数:UIApplication或者其子类 ...

  3. ElasticSearch(二十一)正排和倒排索引

    1.区别 搜索的时候,要依靠倒排索引:排序的时候,需要依靠正排索引,看到每个document的每个field,然后进行排序,所谓的正排索引,其实就是doc values 在建立索引的时候,一方面会建立 ...

  4. SAP 定价

    近几天做门店团购销售订单上传SAP接口程序,SO创建测试过程中, 遇到定价问题,同事在定价过程的增强过不了. VOFM 了解到定价过程是个非常复杂的环节,此处出现程序处理过程中ZMP0定价条件下的价格 ...

  5. linux 基础2-null,cut,wc,head,tail

    一. 特殊文件: /dev/null和/dev/tty Linux系统提供了两个对Shell编程非常有用的特殊文件,/dev/null和/dev/tty.其中/dev/null将会丢掉所有写入它的数据 ...

  6. C#聚合运算方法

    Aggregate 对集合值执行自定义聚合运算 Average 计算集合平均值 Count 对集合的元素惊醒计数,还可以仅对满足某一谓词函数的元素进行计数 LongCount 对大型集合中的元素进行计 ...

  7. 使VS自动生成代码注释

    1.注释模板位置C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE\ItemTemplatesCache 里面有各种脚本的模板 2.找到 ...

  8. mysql主从复制(linux下)

    转至:http://369369.blog.51cto.com/319630/790921 怎么安装mysql数据库,这里不说了,只说它的主从复制,步骤如下: 1.主从服务器分别作以下操作:   1. ...

  9. Spring Cloud之Swagger集群搭建

    在微服务中,Swagger是每个服务 比如会员服务,订单服务,支付服务 进行继承. 如何将整个微服务中的Swagger进行合成,同一台服务器上. 使用Zuul+Swagger实现管理整个微服务API文 ...

  10. 多种方法求java求整数的位数

    方法一 private static int getNumLenght(long num){ num = num>0?num:-num; return String.valueOf(num).l ...