2017.10.5北京清北综合强化班DAY5
拼不出的数
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。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
using namespace std; int n,a[];
LL sum; int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)scanf("%d",&a[i]);
sort(a+,a+n+);
for(int i=;i<=n;i++){
if(a[i]>sum+){
printf("%lld\n",sum+);
return ;
}
sum+=a[i];
}
printf("%lld\n",sum+);
return ;
}
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个数
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std; LL n,ans; int main(){
scanf("%lld",&n);
for(register LL i=;i<=n;i++){
LL a=n/i;
LL b=n/a;
i=b;
ans++;
}
printf("%lld",ans);
return ;
}
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..
也可以打表找规律
#include<iostream>
#include<cmath>
#include<cstdio>
#define LL long long
using namespace std;
LL n;
int main(){
scanf("%lld",&n);
LL k=sqrt(n),ans=k*;
if(k*k<=n&&k*(k+)>n)ans--;
printf("%lld\n",ans);
return ;
}
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越大,差值越小。//我也不太明白这个做法。
我又认真看了看...下面是我的理解...
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cassert>
using namespace std; typedef long long LL;
LL n;
bool check(LL x){ // n <= x*(x+1)
if(x*.*(x+)>1e18) return true;
if(n <= x *(x+)) return true;
return false;
}
int main(){
freopen("div.in","r",stdin);
freopen("div.out","w",stdout);
scanf("%lld",&n);
if(n==){
puts("");
}else if(n==){
puts("");
}else{
LL L = ,R=n-;
while(R-L>){
LL mid = (L+R)/;
if(check(mid)) R=mid;
else L=mid;
}
// assert(check(R));
printf("%lld\n",L+(n/R));
} return ;
}
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分
#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
using namespace std; int n,m;
double ans[];
struct BOX{
int v,p;
}b[]; inline int read(){
char ch=getchar();int x=,f=;
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
for(;isdigit(ch);ch=getchar())x=x*+ch-'';
return x*f;
} void dfs(int x,LL sumz,int sumq,double w){
if(x==n+){
if(sumq>=m)ans[sumz]+=w;
return;
}
dfs(x+,sumz+,sumq,w*(1.0-b[x].p*1.0/));
dfs(x+,sumz,sumq+b[x].v,w*b[x].p*1.0/);
} int main(){
freopen("diamond.in","r",stdin);
freopen("diamond.out","w",stdout);
n=read();m=read();
/*n个盒子 m钱数大于m*/
for(int i=;i<=n;i++){
b[i].v=read();b[i].p=read();
}
/*pi/100的概率获得钱*/
dfs(,,,1.0);
/*目前看第1个盒子,钻石数和钱数为0
当前情况出现的概率为0.0
*/
for(int i=;i<=n;i++)
printf("%.3lf\n",ans[i]);
fclose(stdin);fclose(stdout);
return ;
}
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的乘积。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
int tt;
int n,m;
int v[];
double p[];
double ans[];
vector<pair<int,double> > sta[];
int main(){
freopen("diamond.in","r",stdin);
freopen("diamond.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=,x;i<=n;i++){
scanf("%d%d",&v[i],&x);
p[i]=x/.;
}
for(int i=;i<=n;i++){
sta[i].clear();
}
int an=(n/2.5)+;
int bn=n-an;
for(int st=;st<<<bn;st++){
double nowp=;
int cnt=,money=;
for(int i=;i<bn;i++){
if((st>>i)&){
money+=v[n-i];
nowp*=p[n-i];
}else{
cnt++;
nowp*=(-p[n-i]);
}
}
sta[cnt].push_back(make_pair(money,nowp));
}
for(int i=;i<=n;i++){
sort(sta[i].begin(),sta[i].end());
for(int j=;j<sta[i].size();j++){
sta[i][j].second+=sta[i][j-].second;
}
}
for(int st=;st<<<an;st++){
double nowp=;
int cnt=,money=;
for(int i=;i<an;i++){
if((st>>i)&){
money+=v[i+];
nowp*=p[i+];
}else{
cnt++;
nowp*=(-p[i+]);
}
}
for(int i=;i<=bn;i++){
// now d =cnt+i
int L = m-money;
vector<pair<int,double> >::iterator it = lower_bound(sta[i].begin(),sta[i].end(),make_pair(L,-.));
double tmp = sta[i].back().second;
if(it!= sta[i].begin()){
it--;
tmp-=it->second;
}
ans[cnt+i] += tmp*nowp;
}
}
for(int i=;i<=n;i++){
printf("%.3f\n",ans[i]);
}
fclose(stdout);
return ;
}
AC
2017.10.5北京清北综合强化班DAY5的更多相关文章
- 2017.10.3北京清北综合强化班DAY3
括号序列(bracket) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法的 ...
- 2017.10.4北京清北综合强化班DAY4
财富(treasure) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...
- 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]的倍 ...
- 2017.10.6北京清北综合强化班DAY6
题目大意:改变一个数的位置 把一个序列变成不下降序列 题解: 设置一个pre,如果破坏单调性,就把‘删除’这个.否则把pre修改为当前元素的值. 考试时这样得了90分,是因为我的做法只能过这样的数据 ...
- 2017.10.1北京清北综合强化班DAY1
a[问题描述]你是能看到第一题的 friends 呢.——hja何大爷对字符串十分有研究,于是天天出字符串题虐杀 zhx. 何大爷今天为字符串定义了新的权值计算方法.一个字符串 由小写字母组成,字符串 ...
- 2017.10.2北京清北综合强化班DAY2
a[问题描述]你是能看到第一题的 friends呢. —— hja世界上没有什么比卖的这 贵弹丸三还令人绝 ...
- 北京清北 综合强化班 Day5
T1 思路: 输入数据,sort一下, 如果a[i]>sum+1(前缀和) 那么sum+1就一定不会被拼出来, 然后输出即可. 上代码: #include <iostream> #i ...
- 北京清北 综合强化班 Day4
财富(treasure) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有n个小伙伴.每个小伙伴有一个身高hi. 这个游戏是这样的,LYK生活的环境是以 ...
- 北京清北 综合强化班 Day3
括号序列(bracket) Time Limit:1000ms Memory Limit:128MB 题目描述 LYK有一个括号序列,但这个序列不一定合法. 一个合法的括号序列如下: ()是合法的 ...
随机推荐
- 将非递减有序排列(L L1)归并为一个新的线性表L2 线性表L2中的元素仍按值非递减
#include "stdio.h"#include "stdlib.h"#include "function.h"void main(){ ...
- Spring框架结构
在processOn思维导图上看的一个程序员写的,挺不错的,分享出来,便于学习和回顾.
- Android 新建一个类,在src新建一个类,使继承自活动
一:先新建一个包 右键src,新建包: 二:包中新建类 右建包,新建类,将超类改为andorid.app.Activity
- python解释器安装教程
1. 首先,打开python的官网:python.org 2. 首页downloads下打开, 3. 最上边是两个最新的版本,长期计划,推荐使用python3,如果长期打算用p3,默认使用最新版本.如 ...
- 九度OJ 1326:Waiting in Line(排队) (模拟)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:220 解决:64 题目描述: Suppose a bank has N windows open for service. There is ...
- python查询IP地址所属地
1.linux命令行版 #!/usr/bin/python #-*- coding: utf-8 -*- import json import urllib import sys def get_da ...
- zabbix 主机组管理
分组的目的是将同一属性的主机归类,主机组中可以包含主机,也可以包含模板 建议:同一属性的主机或者模板,尽量归纳到分组中方便以后管理.分组原则如下: 以地理位置进行划分 以业务划分 以机器用途划分 以系 ...
- web前端开发-Ajax(2)
前面的一篇博文简单的简绍了Ajax基于jQuery的用法,接下来要对Ajax做进一步的介绍,Ajax请求大致可以通过三种方式发送:原生Ajax,jQuery,伪Ajax.1.原生Ajax: 由于Aja ...
- 找到最大或最小的N个值
对于python原生的数据类型来说,并不存在直接的方法可以找到最大或最小的N个值, 传统的方法必须先排序,然后再截取相应的值,而且对于集合这类数据类型来说还不能直接排序, 需要先转化为列表才行,有的时 ...
- 有关java之反射的使用
1 public class Demo02 { 2 @SuppressWarnings("all") 3 public static void main(String[] args ...