[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次:
- 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!
[20180815]校內模擬賽