T1 拼不出的数

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 <=109。

考场中没有看到1<=ai<=10^9,认为a一定是在n的范围内的,然后完美的开了三个1000的数组,然后就崩溃了、、

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 110000
#define LL long long
using namespace std;
LL n,a[N],tot;
bool vis[N],vist[N];
LL read()
{
    LL x=,f=; char ch=getchar();
    ') ch=getchar();
    +ch-',ch=getchar();
    return x*f;
}
void dfs(int now,int s,int sum)
{
    if(now==s)
    {
        vist[sum]=;
        return ;
    }
    ;i<=n;i++)
    {
        if(vis[i]) continue;
        vis[i]=;
        dfs(now+,s,sum+a[i]);
        vis[i]=;
    }
}
int main()
{
//    freopen("lost1.in","r",stdin);
//    freopen("lost.out","w",stdout);
    n=read();
    ;i<=n;i++) a[i]=read(),tot+=a[i];
    ;i<=n;i++)
      dfs(,i,);
    ;i<=tot+;i++)
    {
        if(vist[i]) continue;
        printf("%lld",i);
        ;
    }
}

考场暴零代码

一个思路题吧、、(代码很短)

我们读入所有的a以后先对其进行一个sort排序,然后我们在观察我们排序后的a数组,我们可以知道当前面的前缀和加1不等于当前数,那么这个前缀和加1,就是我们要求的最小的不能被拼出的数。

正确性证明??

我们来看一组数 12  14 5  6  21  7  1  2  4 13 我们将这一组数排完序以后将会变成 1  2  4  5  6  7  12  13  14  21

假设我们不存在1这个数,那么我们最初拼出的数为2,那么1一定是不会被频出的最小的数,也就是结果。然后我们看当前数组,1跟2能拼成1 、2、 3我们判断当前前缀和也就是最大能拼出的数+1以后是否大于等于当前数,我们继续往下走3+4=7,现在用这些数我们可以拼出1~7内的所有的数,然后在判断3+4+5+6+7+12+13+14=64这样的话我们最小的不能拼成的数为64+1=65.

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 100010
#define LL long long
using namespace std;
int n,a[N];
int read()
{
    ,f=; char ch=getchar();
    ;ch=getchar();}
    +ch-',ch=getchar();
    return x*f;
}
int main()
{
    n=read();
    ;i<=n;i++) a[i]=read();
    sort(a+,a++n); LL sum=;
    ;i<=n;i++)
     <a[i]) {printf(); ;}
     else sum+=a[i];
    printf();
    ;
}

AC代码

T2 整除

题目描述

给定整数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。

输出格式:

一行一个整数答案。

输入输出样例

输入样例#1:

5
输出样例#1:

3

说明

对于30% 的数据,满足1 <=n <= 10^3。

对于60% 的数据,满足1 <= n <=10^12。

对于100% 的数据,满足1 <=n <=10^18。

打表找规律80分

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
LL n,ans,tot,sum;
LL read()
{
    LL x=,f=; char ch=getchar();
    ') ch=getchar();
    +ch-',ch=getchar();
    return x*f;
}
int main()
{
    freopen("div.in","r",stdin);
    freopen("div.out","w",stdout);
    tot=;n=read();
    ;};
    ) {puts(;};
    while(sum<n)
    {
        ans++;
        ==) sum=sum+tot;
        else sum=sum+tot,tot++;
    }
    ) ans=;
    printf("%lld",ans);
    ;
}

80分代码

打表找规律,我们打一个表出来以后会发现一个规律,每一个数的结果与根号n有一个比较密切的联系

我们先打一个10以内的表

n ans 根号n  
1 1 1 1*2-1=1
2 2 1 1*2=2
3 2 1 1*2=2
4 3 2 2*2-1=3
5 3 2 2*2-1=3
6 4 2 2*2=4
7 4 2 2*2=4
8 4 2 2*2=4
9 5 3 2*3-1=5

通过上面的表,我们是不是可以发现这样一个小规律,每一个数的开跟*2或*2-1跟我们的答案有着密切的联系。我们还可以发现当一个数的跟n等于n/跟n,也就是说我们拼出来的两个数是一样的时候我们要对最终答案-1

#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
long long n,ans;
long long read()
{
    ,f=; char ch=getchar();
    ; ch=getchar();}
    +ch-',ch=getchar();
    return x*f;
}
int main()
{
    n=read();
    ans=sqrt(n);
    -;
    ;
    printf("%lld",ans);
}

AC代码

T3 钻石

题目描述

你有n 个“量子态” 的盒子,每个盒子都可能是一些钱也可能是一个钻石。

现在你知道如果打开第i 个盒子,有pi/100 的概率能获得Vi 的钱,有

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

现在你想知道,自己恰好获得k(0 <= k <=n) 个钻石,并且获得钱数大

于等于m 的概率是多少。

请你对0 <= k <= n 输出n+1 个答案。

答案四舍五⼊保留3 位⼩数。

输入输出格式

输入格式:

第⼀⾏两个整数n,m,见题意。

接下来n 行,每行两个整数Vi; Pi。

输出格式:

输出共n+1 行,表示0 <=k <= n 的答案。

输入输出样例

输入样例#1:

2 3
2 50
3 50
输出样例#1:

0.250
0.250
0.000

说明

对于30% 的数据, n <=10。

对于60% 的数据, n <=15

对于100% 的数据,n <= 30; 1 <= Pi <= 99; 1 <= Vi <= 10^7; 1 <=m <=10^7。

暴力搜索60

我们搜索从每一个盒子中取出钻石还是钱,分别算出其概率,然后我们在所有的盒子都打开以后判断当前这种情况获得的钱数是否大于等于m,如果是的话ans[s]更新,s为钻石数目,我们用一个ans数组统计获得几颗钻石的情况下的概率。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 50
using namespace std;
double ans[N];
int n,m,v[N],p[N];
int read()
{
    ,f=; char ch=getchar();
    ;ch=getchar();}
    +ch-',ch=getchar();
    return x*f;
}
void dfs(int now,int s,int c,double w)
{
    )
    {
        if(c>=m) ans[s]+=w;
        return ;
    }
    dfs(now+,s+,c,w*());
    dfs(now+,s,c+v[now],w*p[now]*);
}
int main()
{
    n=read(),m=read();
    ;i<=n;i++) v[i]=read(),p[i]=read();
    dfs(,,,1.0);
    ;i<=n;i++)
     printf("%.3lf\n",ans[i]);
    ;
}

60分搜索

正解为双向搜索,meet in the middle

我们通过前面的可以看到暴力搜索的话只能拿到60分,我们要想一个办法对这个搜索进行优化,我们可以先搜后一半,然后在前一半中找出与后一半合并以后能满足条件的状态,

满足的条件就是钱数>=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的乘积。

(具体做法在代码中有注释)

#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 50
using namespace std;
double p[N],ans[N];
int n,m,x,a,b,v[N];
vector<pair<int,double> >vec[N];
int read()
{
    ,f=; char ch=getchar();
    ;ch=getchar();}
    +ch-',ch=getchar();
    return  x*f;
}
int main()
{
    n=read(),m=read();
    ;i<=n;i++) v[i]=read(),x=read(),p[i]=x/.;
    a=(n+)/;b=n-a;//由于我们要折半处理,因此我们现将其盒子分成两半
    ;i<=n;i++)
        vec[i].clear();//可有可无、、
    //对于每一种状态我们可以用个三元组表示{a,b,c}表示状态的钻石个数为a,钱数为b,概率为c
    ;st<<<b;st++)//我们先处理后一半盒子
    {
        ;
        ,money=;//赋初值
        ;i<b;i++)//这个与前面构成一个大枚举,当前盒子为钻石还是钱
        {
            )//当前盒子中为钱
             money+=v[n-i],np*=p[n-i];//钱的总数增加,概率相乘
            else
             s++,np*=(-p[n-i]);//钻石数+1
        }
        vec[s].push_back(make_pair(money,np));//我们将我们处理出来的所有情况储存在vec中
    }
    //我们处理了后一半的所有状态 ,将其存在vec数组中
    //接下来的这个地方我们对我们处理出来的每一个数做一个分块处理,钻石数为0的放在一起,钻石数为1的放在一起,钻石数为2的放在一起、、、、并且对于每一块做概率的前缀和
    ;i<=n;i++)
    {
        sort(vec[i].begin(),vec[i].end());//我们将最小的可能不满足条件的放在前面,那么我们找出第一个满足条前的位置的时候,我们就可以知道在这个位置往前的一定都不满足条件
        ;j<vec[i].size();j++)
         vec[i][j].second+=vec[i][j-].second;
    }
    //这个地方我们可以知道a*b+a*c+a*d=a*(b+c+d)而这个地方的(b+c+d)为后半段所有满足条件的概率总和,那么我们在这个地方就可以预处理一个前缀和
    ;st<<<a;st++)//我们再来根据搜出来的后半段的状态来找前半段的状态
    {
        ;
        ,money=;
        ;i<a;i++)
        {
            )
             money+=v[i+],np*=p[i+];
            else
             s++,np*=(-p[i+]);
        }
        //找能与搜出的前半段的状态合并起来以后能满足条件的后半段
        //钻石数为s+i的这种状态可以由我们当前搜到的状态(存在了s颗钻石)我们可以再加上i颗钻石以后的钱数就可以满足条件,枚举这个可以使他满足条件的i
        ;i<=b;i++)//后一半一共有b个位置,总共就有b+1个状态,我们按照钻石的个数为一个状态
        {
            int l=m-money;//我们当前搜到的前半段的钱数已经是money了,那么我们还剩下m-money的钱数就可以满足条件
            vector<pair<int,double> >::iterator it=lower_bound(vec[i].begin(),vec[i].end(),make_pair(l,1.0));//获得第一个满足条件的位置
            //我们找出第一个满足条件的位置 用it来记录
            //我们可以认为vec为一个数组
            double tmp=vec[i].back().second;//现将tmp初始为整个数组的值
               if(it!=vec[i].begin())//我们判断当期位置是否为数组的第一个位置,如果是的话就说明数组中的每一种状态都满足条件,总概率即为tmp
              it--,tmp-=it->second; //如果不是的话,那么it为第一个满足条件的位置,it-1就是第一个不满足条件的位置,我们在减去it-1这一部分的前缀和,那么剩下的就是所有的满足条件的概率
            ans[s+i]+=tmp*np;//搜到当前钻石数的概率为前半段的概率*后半段的概率
        }
    }
    ;i<=n;i++)
     printf("%.3lf\n",ans[i]);
    ;
}

AC代码

10.1综合强化刷题 Day5的更多相关文章

  1. 10.1综合强化刷题 Day3 morning

    竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试点时限 1s 1s ...

  2. 10.1综合强化刷题 Day3 afternoon

    竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试点时限 1s 1s ...

  3. 10.1综合强化刷题 Day2 morning

    一道图论神题(god) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图,只有 ...

  4. 10.1综合强化刷题 Day2 afternoon

    最大值(max) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一本书,上面有很多有趣的OI问题.今天LYK看到了这么一道题目: 这里有一个长度为n的 ...

  5. 10.1综合强化刷题 Day7

                                                                                       noip提高组模拟赛       ...

  6. 10.1综合强化刷题 Day1 afternoon

    一道图论好题(graph) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK有一张无向图G={V,E},这张无向图有n个点m条边组成.并且这是一张带权图, ...

  7. 10.1综合强化刷题 Day6

    T1 排序 题目描述 小Z 有一个数字序列a1; a2; .... ; an,长度为n,小Z 只有一个操作:选 定p(1<p<n),然后把ap 从序列中拿出,然后再插⼊到序列中任意位置. ...

  8. 10.1综合强化刷题 Day4

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

  9. 10.1综合强化刷题 Day3

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

随机推荐

  1. 手机注册过哪些网站37kfenxi.com,查询注册过哪些网站

    注册过哪些网站?发现这么一个网站,https://www.37kfenxi.com?_=cnblogs 可以根据手机号码查询注册过哪些网站,然后通过大数据分析出机主的性格,爱好等. 据说还可以查老板, ...

  2. 第2章c++简单程序设计

    第2章c++简单程序设计 知识梳理 以下是我遗忘以及认为重要的知识整理: 1.标识符的构成规则: 以大写字母.小写字母或下划线 _ 开始 由大写字母.小写字母.下划线 _ 或数字(0~9)组成 大写字 ...

  3. C++文件读写之对象的读写

    这里以一个简单的学生信息管理系统为例. 首先是对象的建立,包括姓名,学号,成绩,学分,等 如下: 这里面包括两个子对象, class Student { public: Student() :scor ...

  4. git:多个sshkey配置

    克隆项目: 使用git clone +项目.git地址 例如: 创建SSH Key: ssh-keygen -t rsa -C +邮箱地址 sshkey自定义保存:创建后在第二步(enter file ...

  5. 获取表的字段例如 col1,col2,col3

    create function [dbo].[f_getcolsByName](@tableName varchar(50)) returns varchar(1000)asbegin declare ...

  6. [python][django学习篇][14]markdown 代码高亮

    1 修改detail视图函数,渲染文件的时候,增加codehight拓展 post.body = markdown.markdown(post.body, extensions=[ 'markdown ...

  7. Python-伪私有属性

    原文:http://blog.itpub.net/26250550/viewspace-1411768/ 通常在 Python 中,我们都被告知可以使用双下划线开头的方法名定义方法来达到私有函数的目标 ...

  8. redhat-2

    2016年5月16日-工作日志1 通过PXE安装RHEL7.2系统,部署satellite6.2(采用不是least-stable版本,是Satellite-6.2.0-RHEL-7-20160512 ...

  9. VC++中PostMessage、SendMessage和PeekMessage之间的区别

    1, PostMessage只把消息放入队列,不管其他程序是否处理都返回,然后继续执行,这是个异步消息投放函数.而SendMessage必须等待其他程序处理消息完了之后才返回,继续执行,这是个同步消息 ...

  10. iOS-------- Objective-C多态:动态类型识别+动态绑定+动态加载

    一.Objective-C多态 1.概念:相同接口,不同的实现 来自不同类可以定义共享相同名称的方法. 动态类型能使程序直到执行时才确定对象所属类型 动态类型绑定能使程序直到执行时才确定要对对象调用的 ...