Task 1:子集

【问题描述】

 若一个集合S中任意两个元素x和y,都满足x⊕y<min⁡(x, y) ,则称集合S是“好的”。其中⊕为按位异或运算符。现在给定一个大小为n的集合S,其中每个数字都是正整数,请求出S所有“好的”子集中,元素个数最多的集合大小。

【输入】

 输入文件含有多组数据

 每组数据第一行读入元素个数N。接下来一行,N个正整数ai描述集合中的元素。

【输出】

 对于每组测试数据,输出一行一个整数表示答案.

subset.in subset.out
3 2
1 2 3 2
2
1 1

【样例解释】

 第一组数据中,选择集合{2,3}为最佳方案。若选择{1,2,3},由于1⊕2=3>min(1,2) ,该集合不是“好的”。

【数据范围】

  • $1 – 4 $ \(1 ≤ N ≤ 16\)

  • $5 – 10 $ \(1 ≤ N ≤ 1000\)

  • 对于100%的数据:\(1 ≤ ai ≤ 10^9\)。

 异或又名半加,可以理解为不进位加法。

 考虑三种形式:

  • 1^1=0
  • 0^0=0
  • 1^0=1

 只考虑最高位,若要使异或结果比两个数都小,最高位只能满足情况1。所以就可以直接按照二进制最高位数拆分,每个位数作为一个集合,求最大集合。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,arr[1010],bin[40],res[40];
inline int read(){
int s=0;
char ch=getchar();
while('9'<ch||ch<'0'){
ch=getchar();
}
while('0'<=ch&&ch<='9'){
s=(s<<3)+(s<<1)+ch-'0';
ch=getchar();
}
return s;
}
int main(){
freopen("subset.in","r",stdin);
freopen("subset.out","w",stdout);
bin[0]=1;
for(register int i=1;i<=30;++i){
bin[i]=bin[i-1]<<1;
}
while(scanf("%d",&n)==1){
memset(res,0,sizeof(res));
for(register int i=1;i<=n;++i){
arr[i]=read();
int pos=upper_bound(bin,bin+31,arr[i])-bin;
res[pos]++;
}
int ans=0;
for(register int i=0;i<=30;++i){
ans=max(ans,res[i]);
}
printf("%d\n",ans);
}
return 0;
}

Task 2:出行

【问题描述】

 小C要从A地赶往B地,A地和B地相距L米。在A去往B的路上,还有N个咖啡站,其中第i个咖啡站在距离A地xi 米的位置(0≤x1<x2<…<xN≤L )。小C平时步行的速度为a米/秒,而当他喝咖啡时,步行速度会是b米/秒(a<b )。

 每当小C到达一个咖啡站,小C可以选择购买一杯咖啡,购买咖啡所花费的时间可以忽略不计。刚买的咖啡由于太烫还不能立即饮用,所以小C会继续以a米/秒的速度前进。在买完咖啡t秒后,咖啡才变得可以饮用,此时小C便开始以b米/秒的速度前进。小C喝一杯咖啡需要r秒,即从开始喝咖啡r秒后,小C的前进速度又会变回a米/秒。当然小C到达咖啡站时,也可以选择不购买咖啡。

 另外,如果小C选择在一个咖啡站停下来购买咖啡,但此时手上还有一杯没有喝或者没喝完的咖啡,那么小C会毫不犹豫地扔掉手上之前购买的咖啡。

 请求出在最优决策下,小C从A地前往B地最少需要花费多少秒。

【输入】

 第一行,五个整数L,a,b,t,r,分别表示两地间距离,小C不喝咖啡及喝咖啡时的速度,咖啡变凉的时长,以及饮用一杯咖啡需要的时间。

 第二行,一个整数N,描述A地到B地之间咖啡站的数量。

 接下来一行,N个单调上升的整数,表示第i个咖啡站与A地的距离。

【输出】

 一行,表示答案,相对误差或绝对误差与标准答案相差不超过10^-6 即被认为正确。

walk.in walk.out
80 1 2 20 10 60
3
0 20 40

【样例解释】

 最优决策下,小C会选择在第一个和第三个咖啡站买咖啡,第一次买咖啡时,小C以1米/秒的速度前进20秒,此时咖啡不再烫嘴,再以2米/秒的速度前进10秒,此时恰好到达第三个咖啡站。可以计算,最优花费为2*(10+20)=60 秒。

【数据范围】

  • \(1 – 2\) \(0 ≤ N ≤ 20\)
  • \(3 – 6\) $ 0 ≤ N ≤ 1000$
  • \(7 – 10\) $ 0 ≤ N ≤ 5*10^5$
  • 对于100%的数据:保证\(1≤L≤10^{11} ,1≤a<b≤200 ,0≤t≤300 ,1≤r≤1200\)

 考虑路径为双色线段,前一半等待后一半加速。

 首先有一点可以确定:如果当前线段起点在某个线段加速点之前,从这个线段的转移一定不是最优。

 原因:前一个点选择而加速并未使用,直接转移一定不会最优。

 其他的情况分两类:

  • 当前的线段起点在某个线段加速点之后:部分加速
  • 当前线段起点在某个线段终点之后:完全加速,直接转移

 考虑直接转移:60pts

 因为我太弱了所以并没有摸索出来第一种情况怎么优化,只做了一个对第二种情况的单调队列加速。60pts->80pts

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define MAXN 500010
#define lint long long
using namespace std; lint n,l,sl,fa,wt,dr,head=1,tail=0,f[MAXN],que[MAXN];
bool vis[MAXN];
struct node{
lint pos;
lint fas;
lint fin;
}nod[MAXN];
inline lint min(lint x,lint y){
return x<y?x:y;
}
inline void update(lint k){
while(head<=tail && que[tail]<=k){
--tail;
}que[++tail]=k;
}
int main(){
freopen("walk.in","r",stdin);
freopen("walk.out","w",stdout);
scanf("%lld%lld%lld%lld%lld%lld",&l,&sl,&fa,&wt,&dr,&n);
for(int i=1;i<=n;++i){
scanf("%lld",&nod[i].pos);
nod[i].fas=min(l,nod[i].pos+sl*wt);
nod[i].fin=min(l,nod[i].fas+fa*dr);
}
nod[++n]=(node){l,l,l};
for(register int i=1;i<=n;++i){
f[i]=nod[i].fin-nod[i].fas;
for(register int j=i;j>=1;--j){
if(nod[i].pos<=nod[j].fas)continue;
if(nod[i].pos>=nod[j].fin){
if(vis[j])break;
update(f[j]);
f[i]=max(f[i],nod[i].fin-nod[i].fas+que[head]);
vis[j]=true;
}else{
f[i]=max(f[i],f[j]-(nod[j].fin-nod[i].pos)+nod[i].fin-nod[i].fas);
}
}
}
double ans=(double)f[n]/(double)fa+(double)(l-f[n])/(double)sl;
printf("%lf\n",ans);
}

 调了一上午的100pts:不咕了在下面

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 1000010
#define int long long
using namespace std;
struct node{
int pos;
double val;
}que[MAXN];
double f[MAXN];//f记录到达每一个咖啡站的花费时间
int l,n,a,b,t,r,x[MAXN];
//vis用于记录对于一个能完整喝完咖啡的选择,以前是否访问过
signed main(){
freopen("walk7.in","r",stdin);
// freopen("walk.out","w",stdout);
memset(que,0,sizeof(que));
cin>>l>>a>>b>>t>>r>>n;
for(int i=1;i<=n;++i){
scanf("%lld",&x[i]);
}
double minn=1e50;
int head=1,tail=0,p1=1,p2=1,fst=0;
x[++n]=l;
for(int i=1;i<=n;++i){
//在这个点以前的选择都已经被处理过
while(x[i]-x[p1]>=t*a+r*b && p1<i){
//是一个可以完整喝完的选择
minn=min(minn,(double)f[p1]+(double)r-( (double)x[p1]+(double)(r*b))/((double)a));
p1++;
fst=1;
}//更新可用最小值
if(t*a<=x[i]-x[p2] && x[i]-x[p2]<t*a+r*b && p2<i){
double ins=(double)f[p2]+(double)t-((double)(x[p2]+a*t))/(double)b;
while(head<=tail && ins<=que[tail].val)tail--;
que[++tail].val=ins;
que[tail].pos=x[p2];
p2++;
}
while(head<=tail && que[head].pos<=x[i]-t*a-r*b)head++;
f[i]=f[i-1]+((double)(x[i]-x[i-1]))/(double)a;
f[i]=min(f[i],minn+(double)x[i]/(double)a);
if(head<=tail){
f[i]=min(f[i],que[head].val+(double)x[i]/(double)b);
}
}
printf("%.8lf",f[n]);
}

Task 3:游戏

【问题描述】

 有一个长度为n的排列,小C可以交换任意相邻元素任意多次,但第i 次交换需要付出i 的代价。小C认为逆序对是丑陋的,若在小C操作完的序列中共有x 个逆序对,那么小C就会认为这个序列的丑陋度是B*x ,其中B 是给定的常数。小C希望你告诉他最佳的操作策略,使得最终的序列丑陋度和操作所付出的代价之和最小。

【输入】

 第一行,两个整数n ,B。

 接下来一行,n 个整数,描述初始排列。

【输出】

 一行,表示代价与丑陋度的最小和。

game.in game.out
3 2 3
3 1 2

【样例解释】

 若不操作,代价+丑陋度=0+4=4

 若交换1和3,序列变成{1 3 2},代价+丑陋度=1+2=3

 若交换1和3,再交换2和3,序列变成{1 2 3},代价+丑陋度=3+0=3

 容易验证其他策略下,代价和丑陋度之和都不会小于3

【数据范围】

  • \(1–2\) \(1 \leq N \leq 20\) \(1\leq N\leq20\)
  • \(3-6\) \(1 ≤ N \leq 5000\)
  • \(7 - 10\) \(1 ≤ N ≤ 5*10^4\)
  • 对于100%的数据:\(0 ≤ B ≤ 10^{15}\)

 逆序对水题,只要有逆序对就一定可以交换去掉,每次交换只能去掉一个。只需要求一下逆序对总数就可以了。B和n范围差距悬殊,为了避免高精度计算,可以先把换掉第n个逆序对的最大消耗和B比较一下,再确认是部分换还是全换。

 虽然水但有一点还是很重要的,就是要熟练归并和树状数组求逆序对的方法。

#include<cstdio>
#include<cstring>
#include<iostream>
#define MAXN 50010
#define lowbit(x) x&-x
#define lint long long
using namespace std;
lint n,k,arr[MAXN],tree[MAXN];
inline void add(int pos,int val){
while(pos<=n){
tree[pos]+=val;
pos+=lowbit(pos);
}
}
inline lint getsum(lint pos){
lint res=0;
while(pos){
res+=tree[pos];
pos-=lowbit(pos);
}
return res;
}
inline lint get_rev(){
lint res=0;
for(register int i=n;i>=1;--i){
res+=getsum(arr[i]);
add(arr[i],1);
}
return res;
}
int main(){
freopen("game.in","r",stdin);
freopen("game.out","w",stdout);
scanf("%lld%lld",&n,&k);
for(register lint i=1;i<=n;++i){
scanf("%lld",&arr[i]);
}
lint tot=get_rev(),ans=tot*k;
// printf("tot=%lld\n",tot);
for(register lint i=1;i<=tot;++i){
if(i>=k)break;
ans+=i-k;
}
printf("%lld\n",ans);
return 0;
}

【清北学堂2018-刷题冲刺】Contest 6的更多相关文章

  1. 2017 清北济南考前刷题Day 7 afternoon

    期望得分:100+100+30=230 实际得分:100+100+30=230 1. 三向城 题目描述 三向城是一个巨大的城市,之所以叫这个名字,是因为城市中遍布着数不尽的三岔路口.(来自取名力为0的 ...

  2. 2017 清北济南考前刷题Day 1 afternoon

    期望得分:80+30+70=180 实际得分:10+30+70=110 T1 水题(water) Time Limit:1000ms   Memory Limit:128MB 题目描述 LYK出了道水 ...

  3. 2017 清北济南考前刷题Day 3 morning

    实际得分:100+0+0=100 T1 右上角是必败态,然后推下去 发现同行全是必胜态或全是必败态,不同行必胜必败交叉 列同行 所以n,m 只要有一个是偶数,先手必胜 #include<cstd ...

  4. 2017 清北济南考前刷题Day 3 afternoon

    期望得分:100+40+100=240 实际得分:100+40+100=240 将每个联通块的贡献乘起来就是答案 如果一个联通块的边数>点数 ,那么无解 如果边数=点数,那么贡献是 2 如果边数 ...

  5. 2017 清北济南考前刷题Day 4 afternoon

    期望得分:30+50+30=110 实际得分:40+0+0=40 并查集合并再次写炸... 模拟更相减损术的过程 更相减损术,差一定比被减数小,当被减数=减数时,停止 对于同一个减数来说,会被减 第1 ...

  6. 2017 清北济南考前刷题Day 7 morning

    期望得分:100+50+20=170 实际得分:10+50+20=80 1. 纸牌 题目描述 在桌面上放着n张纸牌,每张纸牌有两面,每面都写着一个非负整数.你的邪王真眼可以看到所有牌朝上的一面和朝下的 ...

  7. 2017 清北济南考前刷题Day 6 afternoon

    期望得分:100+100+30=230 实际得分: 正解: 枚举最高的位,这一位m是1但实际用了0 然后剩余的低位肯定是 正数就用1,负数用0 考场思路:数位DP #include<cstdio ...

  8. 2017 清北济南考前刷题Day 6 morning

    T1 贪心 10 元先找5元 20元 先找10+5,再找3张5 #include<cstdio> using namespace std; int m5,m10,m20; int main ...

  9. 2017 清北济南考前刷题Day 5 afternoon

    期望得分:100+100+30=230 实际得分:0+0+0=30 T1 直接模拟 #include<cstdio> #include<iostream> using name ...

  10. 2017 清北济南考前刷题Day 5 morning

    期望得分:100+100+0=200 实际得分: 坐标的每一位不是0就是1,所以答案就是 C(n,k) #include<cstdio> #include<iostream> ...

随机推荐

  1. (转载)C#使用MemoryStream类读写内存

    MemoryStream和BufferedStream都派生自基类Stream,因此它们有很多共同的属性和方法,但是每一个类都有自己独特的用法.这两个类都是实现对内存进行数据读写的功能,而不是对持久性 ...

  2. vim的几个常用操作

    现在很少会有人用vim来写代码,所以vim更常用在server上面编辑配置文件或者少量代码编辑: vim操作命令非常之多,如果仅用作一个配置文件的编辑器,掌握几个常用的操作就够了: 常用的操作其实就是 ...

  3. How to enable mp3 on Ubuntu

    apt install gstreamer1.0 libavcodec57

  4. windows下ping端口

    上图的操作完成以后  进入dos控制台 输入telnet  ip地址  端口号   回车 标识已ping通 ping不通是这种提示

  5. 学习 Spring (一) Spring 介绍

    Spring入门篇 学习笔记 Spring 是什么 Spring 是一个轻量级的 IoC (控制反转)和 AOP (面向切面)的容器框架 框架与类库的区别 框架一般是封装了逻辑.高内聚的,类库则是松散 ...

  6. Java 设计模式 ------ 模板设计模式

    模板设计模式主要来源于生活中有一些事情是有模板可以遵循的.举两个生活中的例子,如泡茶和泡咖啡,看一看. 泡茶有以下四个步骤:  1, 烧开水;  2 把茶放到水杯中; 3,倒入开水; 4, 加糖. 泡 ...

  7. iOS一些高效代码

    一. [Bugly startWithAppId:BUGLY_APP_ID #if DEBUG developmentDevice:YES #endif config:config]; 二.

  8. kubernetes 编排详解 挂载

    ##kube挂载本地磁盘apiVersion: v1 kind: Pod metadata: name: redis spec: containers: - name: redis image: re ...

  9. POJ 3264-Balanced Lineup-RMQ问题

    裸RMQ问题 #include <cstdio> #include <algorithm> #include <cstring> using namespace s ...

  10. Matplotlib学习---用matplotlib画热图(heatmap)

    这里利用Nathan Yau所著的<鲜活的数据:数据可视化指南>一书中的数据,学习画图. 数据地址:http://datasets.flowingdata.com/ppg2008.csv ...