列表

详情


NC20002. [HEOI2012]BRIDGE

描述

fyg背着他的电脑来到河北省来,就是为了见一眼古老的赵州桥。 终于,他来到了赵州桥,放下了电脑,正准备休息。一阵风吹来,从中闪现出一人影。fyg只觉天昏地暗,待得再次睁开眼时,发觉自己已经到了一神奇的国度,置身于一巨大的圆盘之上。放眼看去,四周都是奇形怪状的桥,不远处有一老头盘膝而坐。fyg还沉浸在惊奇之中,老头(难道就是传说中走过赵州桥的张老头!!)便开口了:凡人,你现在在我的世界中,想要出去就要回答我的问题。fyg只得点头,老头继续道:你现在要去闯关,我给你m种颜色,总共有n关(神仙也懂数学,表示压力巨大。。==)。
每一关中有一座桥,在第i关中,桥长度有i个单位,每个单位长度上有2个格子(也就是说这座桥有2i个格子),现在你要计算出:在这座桥上涂色使得桥上相邻格子的颜色不一样总方案数,然后再乘上(2*i)^m。如在第1关,若你手上有2种颜色,分别为蓝色和绿色。则总方案数为2*2*2 =8种,涂色方案数为2(如下图,旋转、翻转相同算不同的方案),然后还要再乘2个2,最后你出来之后我会问你所有关中计算出来的数的和。如果你能答对,我就可以让你出去了,否则就无限轮回吧。 fyg表示这个问题太水了,完全不想算。。。于是, 他马上打开电脑上了QQ找到了喜欢计算的你,求你 帮他直接把最终答案算出来,让他回到赵州桥上。这两个数都有可能很大,fyg 不想为难你,所以你只要告诉他其除以p的余数。

输入描述

只有一行,其中包含四个正数n、m、p,分别由一个空格分开。n、m、p含义和题目描述一致。

输出描述

一行,表示方案数的和除以p的余数。

示例1

输入:

2  5 50

输出:

30

说明:

【样例说明】
总共有2关。
第一关的桥长度为1,总共有2个格子,涂色方案数为20,再乘上2 ^ 5,第一关中 计算出的数为640。
第二关的桥长度为2,总共有4个格子,涂色方案数为260,再乘上4 ^ 5,第二关中 计算出的数为266240。
两个数字加起来除以50余30,故输出为30。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 78ms, 内存消耗: 28024K, 提交时间: 2021-05-27 15:50:37

#include<cstdio>
#include<iostream>
using namespace std;
int f[3005], g[3005], com[3005][3005];
int getmod(long long x, int mod){return x >= mod ? x % mod : x;}
int qp(int a, int x, int mod){
	int i = 1;
	for(;x;x >>= 1, a = getmod(1ll * a * a, mod))if(x & 1)i = getmod(1ll * i * a, mod);
	return i;
}
inline void solve(int n, int m, int mod){
	int i, j, k;
	if(n == 1)for(i = 0;i <= m;i++)f[i] = 1;
	else{
		solve(n >> 1, m, mod);
		j = qp(m * (m - 3) + 3, n / 2, mod);
		for(i = 0;i <= m;i++){
			g[i] = getmod((1ll + j) * f[i], mod);
			for(k = 0;k < i;k++){
				g[i] += 1ll * j * com[i][k] % mod * f[k] % mod * qp(n >> 1, i - k, mod) % mod;
				if(g[i] >= mod)g[i] -= mod;
			}
		}swap(f, g);
		if(n & 1)for(i = 0, j = qp(m * (m - 3) + 3, n - 1, mod);i <= m;i++){
			f[i] += getmod(1ll * j * qp(n, i, mod), mod);
			if(f[i] >= mod)f[i] -= mod;
		}
	}
}
inline int solve2(int n, int x, int mod){
	if(n <= 0)return 0;
	int r = (1ll + qp(x, n >> 1, mod)) * solve2(n >> 1, x, mod) % mod;
	if(n & 1){
		r += qp(x, n, mod);
		if(r >= mod)r -= mod;
	}return r;
}
int main(){
	int n, m, i, j, mod;
	scanf("%d%d%d", &n, &m, &mod);
	for(i = 0;i <= m;i++)
		for(j = com[i][0] = 1;j <= i;j++)
			com[i][j] = (com[i - 1][j] + com[i - 1][j - 1]) % mod;
	if(m == 1)printf("0");
	else if(mod > 3000){
		solve(n, m, mod);
		i = 1ll * f[m] * qp(2, m, mod) % mod * m % mod * (m - 1) % mod;
		printf("%d", i);
	}else{
		int x = m * (m - 3) + 3, s = n >= mod ? 1 + solve2(n / mod - 1, qp(x, mod, mod), mod) : 0;
		for(i = 1, j = 0;i < mod;i++){
			j += 1ll * qp(i, m, mod) * qp(x, i - 1, mod) % mod;
			if(j >= mod)j -= mod;
		}j = 1ll * j * s % mod;
		for(i = n % mod, s = 0;i;i--){
			s += 1ll * qp(i, m, mod) * qp(x, i - 1, mod) % mod;
			if(s >= mod)s -= mod;
		}s = 1ll * s * qp(x, n / mod * mod, mod) % mod;
		j += s;
		if(j >= mod)j -= mod;
		j = 1ll * j * qp(2, m, mod) % mod * m % mod * (m - 1) % mod;
		printf("%d", j);
	}return 0;
}

上一题