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次:
- k是奇数,Alice胜
- 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)。
- 如果往远离这个活动 区间的方向走,会使疲劳值d(pos,i)的基础上在增加走的距离,可以把它看作先原地不动,活动i结束后再走相应的距离,疲劳值不变。
- 如果走到区间里面去,同样也可以先走到活动的边界,剩下的距离留到活动结束后再走。
所以使答案最优的区间:
[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