今天上午訓練賽,沒有激情,果斷水兩道題。
其實每道題都看過,其他題是真不知道算法。等下午講題後上分析吧。下面是水過的兩題。
POJ 1852 Ants (Also UVa 10714)
題意:一根杆上有幾個螞蟻,爬的方向不確定,且兩隻螞蟻碰頭會反向爬。問所有螞蟻掉下杆的最短和最長時間。
引用大牛分析。
對於每一隻螞蟻,它在棍子上面,距離左端點和右端點的距離可能是相等的也可能是不同的。暫時把距離遠的那端叫做遠端,距離近的那端叫做近端。
那麼爲了使得所有花時間最短,就要讓所有的螞蟻都往近端走,最後總間取決於所有螞蟻中近端最遠的那隻螞蟻,它的時間即是最小時間花費。
同理可推得,要使得所花時間最長,就要讓所有螞蟻都往遠端走,這樣最後長時間取決於所有螞蟻中的遠端最遠的那隻螞蟻。
不用去考慮兩隻螞蟻碰頭的情況, 因爲離遠端最遠的那隻一定是在最右邊或者最左邊的那隻螞蟻,那麼當它往遠端方向走時,可能會碰到迎面走來的,那麼他馬上往回走,對面那隻也往回走走,這就相當於“接力”過程,即對面那隻螞蟻替他走這一段本該由他走的路程(整個過程可能會有無數次“接力”,但最終結果都是一樣的,只是這段最遠路程變成由很多隻螞蟻一起完成)。
以及教訓:開數組解決太弱雞了。讀一個處理一個比較高效。
(主要原因是數組開不下= =)
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
inline int max(int a,int b){ return a>b?a:b; }
inline int min(int a,int b){ return a<b?a:b; }
int main(){
int nCase, len, n, dist;
scanf("%d",&nCase);
while(nCase--){
scanf("%d%d",&len, &n);
int minLen = -100, maxLen = -100;
for(int i=0; i<n; ++i){
scanf("%d",&dist);
maxLen = max(maxLen, max(dist, len-dist));
minLen = max(minLen, min(dist, len-dist));
}
printf("%d %d\n", minLen, maxLen);
}
return 0;
}
HDU 5512 Pagodas
乍一看博弈論,其實是找規律。
題意:給出長度n和a,b,a,b處有廟,兩人輪流重建剩下的位置,直到不能重建爲止,每次只能選a+b或者a-b處重建。
分析:若奇異情況(6,8),則其等價於(2,6)(即後者可以生成前者),再推可以得(2);若情況(3,7),等價於(3,4),再等價於(1,3),再等價於(1)。
這正是尋找最大公約數的過程!
gcd(a,b)的倍數即是可以重建的位置,故可以通過n/gcd(a, b)-2的奇偶來判斷先手勝負情況。減2是因爲已有兩座塔a,b。
#include<cstdio>
int gcd(int a, int b)
{
if(a%b == 0) return b;
else return gcd(b, a%b);
}
void solve(int n, int a, int b)
{
int p = gcd(a, b);
int avi = n/p -2;
if(avi&1) printf("Yuwgna\n");
else printf("Iaka\n");
}
int main()
{
int t, kase = 1;
scanf("%d", &t);
while(t--)
{ int n, a, b;
scanf("%d%d%d", &n, &a, &b);
printf("Case #%d: ",kase++);
solve(n, a, b);
}
return 0;
}
PS 第二個人叫做Iaka,第一個字母是大寫的i,不是小寫的L·····mdzz害我WA。