這是第二次參加ZOJ月賽吧,兩次都是爲了準備校賽。第一次也是去年的這個時間,三個人去了機房,用個把小時看完題後,走了兩個。我多呆了半個小時,終於忍受不了機房的鍵盤鼠標聲和題目的複雜程度,也離開了。在刷這次月賽前,做了一下上次月賽的題目,能A四五道,心中竊喜。果然運氣成分還是很大的,若沒有與人討論,今次恐怕又是鴨蛋。
H 3693 Happy Great BG
簡單題,但是出題者神思路。看到有一大堆人WA就感覺不對了,果然在試着保留w的小數點前兩位後依然WA。後面聽學弟說,0.001元及以下都要入到0.01元,簡直是奸商啊。
#include <cstdio>
int n, k, m;
double w;
int main()
{
while(scanf("%d%lf%d", &n, &w, &k) != EOF)
{
n += 2;
n = n-n/k;
printf("%.2lf\n", n*w/2+0.0049999);
}
return 0;
}
E 3690 Choosing number
應是遞推無誤,將滿足這種約數的序列分成三類,分別是有相鄰重複且以大於K的數結束的,有相鄰重複且以小於等於K的數結束的以及沒有相鄰重複的。假設其數量分別爲a[n], b[n], c[n],則遞推公式爲a[n+1] = (m-k)*(a[n]+b[n])+(m-k)*c[n]/m, b[n+1] = k*a[n] + (k-1)*b[n], c[n+1] = (m-1)*c[n]。直接用滾動數組遞推然後超時了,而這些數列顯然是指數級增長的,後來就想求個帶指數的通項,然後二分計算。結果就耗在這上面了,後面看到別人程序裏有定義二維數組,忽然想起還有矩陣加速這個東西。。
但是c[n]前面的係數是(m-k)/m,不是整數,注意到c[1] = m,所以定義d[n] = c[n]/m。【a[n+1] b[n+1] d[n+1]】’ = 【【m-k m-k m-k】【k k-1 0】【0 0 m-1】】*【a[n] b[n] c[n]】',仿照指數的計算快速求得係數矩陣的n-1次方。
#include <cstdio>
#include <memory.h>
#define Mod 1000000007
struct matrix
{
unsigned long long a[3][3];
}p, e;
int n, m, k;
void mmul(matrix a, matrix b, matrix& c)
{
memset(c.a, 0, sizeof(c.a));
for(int i=0; i<3; ++i)
for(int j=0; j<3; ++j)
for(int k=0; k<3; ++k)
{
c.a[i][j] += a.a[i][k]*b.a[k][j];
if(c.a[i][j] >= Mod)
c.a[i][j] %= Mod;
}
}
void mexp(int n)
{
memset(e.a, 0, sizeof(e.a));
e.a[0][0] = e.a[1][1] = e.a[2][2] = 1;
while(n)
{
if(n & 1)
mmul(e, p, e);
n >>= 1;
mmul(p, p, p);
}
}
int main()
{
while(scanf("%d%d%d", &n, &m, &k) != EOF)
{
memset(p.a, 0, sizeof(p.a));
p.a[0][0] = p.a[0][1] = p.a[0][2] = m-k;
p.a[1][0] = k, p.a[1][1] = k-1;
p.a[2][2] = m-1;
mexp(n-1);
unsigned long long sum = 0;
sum += e.a[0][2];
sum += e.a[1][2];
sum += (e.a[2][2]*m)%Mod;
sum %= Mod;
printf("%llu\n", sum);
}
return 0;
}
E題前還寫了A題的一個錯誤算法,等有人寫了解題報告了再補上吧。