ZOJ Monthly March 2013 E & H

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


你可能感兴趣的:(dp,ACM,ZOJ,easy)