zoukankan      html  css  js  c++  java
  • [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
    ",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
    ",ans);
    	return 0;
    }
    





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

  • 相关阅读:
    selenium---元素定位(find_element)
    selenium---八种定位元素方法
    selenium---环境配置
    vue el-table 自适应表格内容宽度
    另类的开发环境搭建
    基于Django+celery二次开发动态配置定时任务 ( 二)
    基于datax的数据同步平台
    mysql常用日期、时间查询
    MySQL数据库管理
    mysql5.7.20多实例编译安装
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/9481119.html
Copyright © 2011-2022 走看看