这是第二次参加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题的一个错误算法,等有人写了解题报告了再补上吧。