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題的一個錯誤算法,等有人寫了解題報告了再補上吧。


發佈了28 篇原創文章 · 獲贊 0 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章