[20180815]校内模拟赛

T1 游戏(game)

问题描述

Alice准备和Bob玩一个游戏,他们先拿出若干堆石子,每一堆里面都有一定数量的石子。

Alice和Bob轮流操作,Alice先手,每次操作需要选择一堆石子数量大等于2的石子,把这堆石子分成两堆。

假设这堆石子中有x个石子,那么可以分成一堆y(1≤y<x)个石子和一堆x-y个石子。

如果轮到一个人操作时没有可选的石子堆,这个人就输了。

Alice有n堆石子,其中第i堆有\(a_i\)个石子,他打算选出其中连续一段石子跟Bob玩。

你需要回答m次询问,每次查询取出第l堆到第r堆石子进行游戏,双方都选择最优策略时谁会获胜。

输入格式

第一行两个正整数n,m。

第二行n个正整数,表示\(a_i\) 。

接下来m行,每行两个正整数l,r,表示一个询问。

输出格式

对于每个询问输出一行“Alice”或“Bob” ,表示答案。

样例

样例输入


2 3
1 2
1 1
2 2
1 2

样例输出


Bob
Alice
Alice

数据范围

对于 100%的数据,n,m,\(a_i\) ≤ 10^5 ,l ≤ r。

Solution

一个大小为n的石子堆可以被分(n-1)次。

对于一段石子,如果能分k次:

  1. k是奇数,Alice胜
  2. k是偶数,Bob胜

前缀和处理。

#include<iostream>
#include<cstdio>
inline long long read(){
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')ch=getchar();ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 100005
long long n,m,a[MN];
int main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    n=read(),m=read();
    register int i,x,y;
    for(i=1;i<=n;i++) a[i]=read()-1+a[i-1];
    while(m--){
        x=read();y=read();
        if((a[y]-a[x-1])&1) puts("Alice");
        else puts("Bob");
    }
    return 0;
}

T2 数字(number)

问题描述

小 D 最近在研究 A+B 问题,可是这个问题对他来说太棘手了,因为他连读入都不会。

小 D 开了两个变量a和b,并且把它们的初值设为1.

接下来他可以添加若干行代码, 每一行可以是\(a = a + b\)或\(b = a + b\)。

已知A+B 问题的样例输出是n,小D 想知道自己至少需要添加多少行代码才能让a和b中至少有一个等于n以通过样例呢?

输入格式

一行一个正整数n。

输出格式

输出一个整数,表示答案。

样例

样例输入


5

样例输出


3

数据范围

对于 100%的数据,n≤ 10^6 。

Solution

枚举最后一步是由那两个数相加得到的,设为A和B。

可以发现倒推回去的过程类似求gcd的过程。

显然A和B必须要互质。

在倒推的过程中计算步数,最后取个min。

#include<iostream>
#include<cstdio>
inline long long read(){
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')ch=getchar();ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 1000005
int n,m;
int ans=MN,N;
inline int gcd1(int x,int y){
    if(y==0) return 0;
    return gcd1(y,x%y)+(x/y);
}
inline int gcd2(int x,int y){
    if(y==0) return x;
    return gcd2(y,x%y);
}
int main(){
    freopen("number.in","r",stdin);
    freopen("number.out","w",stdout);
    n=read();register int i;
    for(i=1;i<=n-i;i++){
        m=gcd2(n-i,i);if(m!=1) continue;
        ans=std::min(ans,gcd1(n-i,i));
    }
    printf("%d\n",ans);
    return 0;
}

T3 旅行(travel)

问题描述

旅行家小C今天在一条数轴上旅游,一开始他位于x。

数轴王国接下来会依次举行n次活动,每次在区间\([l_i,r_i]\)内举行。

在每个活动开始前,小C可以移动任意的距离,从a移动到b会让他积攒|a-b|的疲劳值。

如果一个活动开始时,小C不在活动范围内,他就会不开心,并且如果离活动范围越远他就越不开心

具体地说,如果小C当前位置到活动范围的最短距离为k,小C就会积攒k的疲劳值。

请你求出所有活动结束后小C最小的疲劳值之和。

输入格式

第一行两个正整数n,x。

接下来n行,每行两个正整数\(l_i\) ,\(r_i\) 。

输出格式

输出一个整数,表示答案。

样例

样例输入


5 4
2 7
9 16
8 10
9 17
1 6

样例输出


8

数据范围

对于 100%的数据,n ≤ 5* 10^5 ,x,\(l_i\) ,\(r_i\) ≤ 10^9 。

Solution

维护使答案最优的区间[L,R],初始L=R=x。

设d(X,i)为X位置到活动[li,ri]的最小距离。

假设当前的位置为pos,对于一个活动[li,ri]

(1) pos不在活动区间内

只要不往远离这个活动区间的方向走,或者的走到区间里面去,疲劳值总是一定的,就是d(pos,i)。

  1. 如果往远离这个活动 区间的方向走,会使疲劳值d(pos,i)的基础上在增加走的距离,可以把它看作先原地不动,活动i结束后再走相应的距离,疲劳值不变。
  2. 如果走到区间里面去,同样也可以先走到活动的边界,剩下的距离留到活动结束后再走。

所以使答案最优的区间:[pos,li][ri,pos]

同样的,如果当前pos的区间为[L,R],且[L,R][li,ri]无交,[L,R]应更新为[min(R,ri),max(L,li)]

(2)pos在活动区间内

原地不动会是最优的,这应该比较显然。

同样的,如果当前pos的区间为[L,R],且[L,R][li,ri]相交,[L,R]应更新为原先两个区间的交集,即

[max(L,li),min(R,ri)].

以下是学长的题解:

f[i][j]表示第i个活动后在j的最小疲劳值,对于每个i,先从i-1复制DP值,接下来有两部分计算,第一部分算活动的疲劳值,j<li的加上li-j,j>ri的加上j-ri。第二部分移动,用f[i][j]+1更新f[i][j-1]f[i][j+1]

事实上,对于每个i,把f[i][j]看成关于j的函数,这个函数会由最多三部分组成,第一部分形如y=-x+a,第二部分y=b,第三部分y=x+c,也就是差分恰好形成-1,0,1三段.

考虑用归纳法证明:i=0 f[i][j]=|j-x|,显然满足。i增大时,第一部分计算会让函数再加上一个差分为-1,0,1的函数,差分会变成-2,-1,0,1,2。第二部分计算会让函数的差分绝对值不超过1,差分又会变成-1,0,1。差分为0的那一段就是最小的答案,维护这一段的位置并顺便计算答案即可。

时间复杂度O(n)

#include<iostream>
#include<cstdio>
inline long long read(){
    long long x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')ch=getchar();ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 500005
int n,pos,l,r,L,R;
long long ans;
bool cross(int x,int y,int a,int b){
    long long len=(y-x)+(b-a);
    x=std::min(x,a);
    y=std::max(y,b);
    return len>(y-x);
}
int main(){
    freopen("travel.in","r",stdin);
    freopen("travel.out","w",stdout);
    int n=read();
    pos=L=R=read();ans=0;
    for(int i=1;i<=n;i++){
        l=read(),r=read();
        if(cross(l,r,L,R)){
            L=std::max(l,L);
            R=std::min(r,R);
        }
        else{
            R=std::min(R,r);
            L=std::max(L,l);
            std::swap(L,R);
            ans+=R-L;
        }
    }
    printf("%lld\n",ans);
    return 0;
}


Blog来自PaperCloud,未经允许,请勿转载,TKS!

原文地址:https://www.cnblogs.com/PaperCloud/p/9481119.html

时间: 2024-10-30 20:41:33

[20180815]校内模拟赛的相关文章

2017.6.11 校内模拟赛

题面及数据及std(有本人的也有原来的) :2017.6.11 校内模拟赛 T1 自己在纸上模拟一下后就会发现 可以用栈来搞一搞事情 受了上次zsq 讲的双栈排序的启发.. 具体就是将原盘子大小copy一下排个序 用两个指针维护两个数组(原数据 和 排序后的数据), 即分为1数据和2数组 将小于1指针指向的数据的2数组中的数据全部压入栈中 后进行消除, 将栈栈顶元素与当前1数组中的1指针指向的元素进行比较 相同则消除 后重复过程 直至指针超过N 后判断一下是否两个指针都超过了N... #incl

校内模拟赛 Zbq&#39;s Music Challenge

Zbq's Music Challenge 题意: 一个长度为n的序列,每个位置可能是1或者0,1的概率是$p_i$.对于一个序列$S$,它的得分是 $$BasicScore=A\times \sum_{i=1}^{n}{S_i} \tag{1}$$ $$ combo(i)=\left\{ \begin{aligned} &S_i & &i=1 \\ &combo(i-1)+1 & &i\neq 1 ~\mathrm{and}~ S_i=1 \\ &

[20180816]校内模拟赛

T1 清理(clear) 问题描述 小 C 最近自己开发了一款云盘软件,目前已有??个用户.小C 的云盘上的文件会被后台分成两种类型,活动 文件和非活动文件,活动文件即可能常用的文件,会被放在高速服务器上给用户提供高速下载服务.用户 上传一个文件时,这个文件会被设置为活动文件.由于高速服务器内存大小有限,小 C 需要把一些文件 设为非活动文件,有以下两种设置方式:1.把上传时间前??早的文件全部设为非活动文件:2.把第??个用户上 传的文件全部设为非活动文件.注意这两种方式操作的对象都是所有文件

校内模拟赛T1大美江湖

这就是一个模拟题,注意1234分别对应左右上下横坐标和纵坐标的判断就好了 题解: 需要注意的是,向上取整ceil函数是对于一个double值返回一个double值,也就是说在ceil里面的类型一定要是double,否则会炸 代码: #include<cstdio> #include<iostream> #include<cstdlib> #include<cmath> #include<cstring> #include<string>

校内模拟赛:确定小组

  [问题描述] 有n个人坐成一排,这n个人都在某一个小组中,同一个小组的所有人所坐的位置一定是连续的. 有一个记者在现场进行采访,他每次采访都会询问一个人其所在的小组有多少人,被询问的每个人都给出了正确的答案,但是由于时间仓促,记者不一定询问了每个人,我们记录一个长度为n的答案序列,序列的第i个数表示第i个人的回答,如果为0则表示记者没有询问过这个人. 记者发现,对于一些情况,他可以唯一确定这排所有人的分组,而对于另外一些情况则不能,于是记者开始好奇,对于某一个答案序列,他能不能做到这一点,如

校内模拟赛20170604

香蕉锤--双向链表 #include<iostream> #include<cstdio> using namespace std; inline int read(){ int num=0,t=1;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')t=-1;c=getchar();} while(c>='0'&&c<='9'){num=num*10+c-'0';c=getchar();} ret

5.13 校内模拟赛

... 果然是dalao们做难题做多了后 简单题水不起来了吗.. 5.13解题报告 300分 T1写了差不多30~40分钟 T2写了不到5min (当时怀疑有坑..) T3推了大概1个多小时的式子, 然后又加上调试差不多一个半小时 时间分配就这样..感觉T2出的太过简单了..直接是个模板 T1 并查集 + 乱搞 T2 快速幂模板 T3 Dp T1 : codevs 2796 最小完全图 二次联通门 : codevs 2796 最小完全图 /* codevs 2796 最小完全图 并查集 + 乱搞

校内模拟赛(20170924)

四校很丧,但是学长的题目更简单 lrb学长的题目为什么都要倒着切,不懂QAQ ----------------我是分割线---------------- T1:个人卫生综合征 每天BBS都要从家里经过城市中的一段路到学校刷五三.城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai.bi且有一定的时间花费vi.BBS家编号为1,学校编号为n.今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0.现在他问你改变道路长度之后他到学校

校内模拟赛(20170921)

救命啊,救命啊!学长出丧题啦!!! 学长他们压榨我们的劳动力,然后带着我们的成绩跑了,无奈的我们只好玩命的调程序,把学长留给我们的丧题做完(划掉) 65分的rank 1跑路. ----------------我是分割线---------------- T1:粉饰(decorate) [题目描述] 小D有一块被分为n*m个格子的矩形鱼片.为了装饰鱼片,小D决定给每个格子上色.由于小D很喜欢红白,所以小D给每个格子涂上了红色或白色,第i行第j列的格子颜色记为c[i,j].涂完之后,小D想评估这块鱼片