这是第二次参加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; }