上海理工大学第二届“联想杯”全国程序设计邀请赛 - Little Witch Academia(矩阵快速幂)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了上海理工大学第二届“联想杯”全国程序设计邀请赛 - Little Witch Academia(矩阵快速幂)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出两种型号的瓷砖,尺寸分别是 a ∗ 1 a*1 a1 b ∗ 1 b*1 b1,现在需要填满 w ∗ h w*h wh 的矩阵,需要满足以下两个情况:

  1. 瓷砖不能旋转
  2. 相邻的两行中,前缀和不能有交集

问方案数

题目分析:因为 a , b , w a,b,w a,b,w 都特别小,按照题目要求爆搜以下不难看出,每一行最多有 114 114 114 种方案

对于相邻的两行是否可以放置,我们可以维护一个可行矩阵 m a z e i , j maze_{i,j} mazei,j m a z e i , j = 1 maze_{i,j}=1 mazei,j=1 代表第 i i i 种方案可以和第 j j j 种方案相邻,这个可以在时间复杂度 O ( n 2 ∗ w ) O(n^2*w) O(n2w) 的复杂度下预处理出来,因为时间复杂度还有冗余,所以我还加了个 s e t set set 降低了代码复杂度

那么现在问题转换为:选择任意起点,走 h h h 步后,不同的方案数有多少

矩阵快速幂的模板题,套上模板就好了

代码:

// Problem: Little Witch Academia
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/17574/L
// Memory Limit: 524288 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
    T f=1;x=0;
    char ch=getchar();
    while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=f;
}
template<typename T>
inline void write(T x)
{
    if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
const int mat_size = 150;//矩阵大小,需要乘以2,为了&运算的时候需要二倍的矩阵大小
const int mod=1e9+7;
struct Matrix
{
	long long a[mat_size][mat_size];
	int x, y;//长宽
	Matrix()	//返回0矩阵
	{
		memset(a,0,sizeof(a));
	}
	Matrix(int x,int y)//返回0矩阵,并且x,y赋值
	{
		this->x = x;
		this->y = y;
		memset(a, 0,sizeof(a));
	}
 
	Matrix(int n)	//返回n*n的【单位矩阵】
	{
		this->x=n;
		this->y=n;
		memset(a,0,sizeof(a));
		for (int i = 0; i <n;++i)	a[i][i]=1;
	}
	Matrix operator * (const Matrix &B)//矩阵乘法
	{
		Matrix tmp;
		for (int i = 0; i < x; ++ i)
			for (int j = 0; j < B.y; ++ j)
			{
				tmp.a[i][j] = 0;
				for (int k = 0; k < y; ++ k)
				{
					tmp.a[i][j] = (tmp.a[i][j] + a[i][k] * B.a[k][j] % mod) % mod;
				}
			}
		tmp.x = x;
		tmp.y=B.y;
		return tmp;
	}
	Matrix operator ^ (long long b)//矩阵A的b次方
	{
		Matrix ret = Matrix(x);  
		Matrix A = *this;
		while( b )  
		{  
			if( b & 1 )	ret = ret * A ;  
			b >>= 1 ;  
			A = A * A ;  
		}  
		return ret ;  
	}
	Matrix operator & (int b)//A^0 + A^1+A^2+A^3+++A^n,其中A是矩阵。最后返回的就是一个矩阵
	{
		Matrix ret = *this;
		for (int i = ret.x; i < ret.x * 2; ++ i)	
		{
			ret.a[i-ret.x][i]= 1;
			ret.a[i][i] = 1;
		}
		ret.x <<= 1;
		ret.y <<= 1;
		//pg(ret);
		ret = ret^b;
		ret.x >>= 1;
		ret.y >>= 1;
		for (int i = 0; i < ret.x; ++ i)	
			for (int j = 0; j < ret.y; ++ j)
				(ret.a[i][j] += ret.a[i][j + ret.x])%=mod;
		return ret;
	}
	void pg(Matrix A)
	{
		for (int i = 0; i <A.x; ++i)
		{
			for (int j = 0; j < A.y;++j)	cout<<A.a[i][j]<<" ";cout<<endl;
		}
		cout<<endl;
 
	}
}maze;
int a,b,w,h;
vector<int>tmp;
vector<vector<int>>node;
void dfs(int cur) {
	if(cur>w) {
		return;
	}
	if(cur==w) {
		node.push_back(tmp);
		return;
	}
	tmp.push_back(a);
	dfs(cur+a);
	tmp.pop_back();
	tmp.push_back(b);
	dfs(cur+b);
	tmp.pop_back();
}
bool check(vector<int>a,vector<int>b) {
	set<int>st;
	int sum=0;
	for(auto it:a) {
		sum+=it;
		st.insert(sum);
	}
	sum=0;
	for(auto it:b) {
		sum+=it;
		if(sum!=w&&st.count(sum)) {
			return false;
		}
	}
	return true;
}
void build() {
	maze=Matrix(node.size(),node.size());
	for(int i=0;i<(int)node.size();i++) {
		for(int j=0;j<(int)node.size();j++) {
			maze.a[i][j]=check(node[i],node[j]);
		}
	}
}
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int t;
	cin>>t;
	while(t--) {
		node.clear();
		tmp.clear();
		read(a),read(b),read(w),read(h);
		dfs(0);
		build();
		maze=maze^(h-1);
		LL ans=0;
		for(int i=0;i<maze.x;i++) {
			for(int j=0;j<maze.y;j++) {
				ans=(ans+maze.a[i][j])%mod;
			}
		}
		cout<<ans<<endl;
	}
    return 0;
}

以上是关于上海理工大学第二届“联想杯”全国程序设计邀请赛 - Little Witch Academia(矩阵快速幂)的主要内容,如果未能解决你的问题,请参考以下文章

上海理工大学第二届“联想杯”全国程序设计邀请赛 - Experiment Class(几何+三分套三分)

上海理工大学第二届“联想杯”全国程序设计邀请赛 - Little Witch Academia(矩阵快速幂)

2011年全国大学生程序设计邀请赛(福州)

2021 ICPC全国邀请赛(西安)太原理工大学收获3枚奖牌

FZU - 2039 Pets (二分图匹配 2011年全国大学生程序设计邀请赛(福州))

“杭银理财”杯浙江工业大学大学生程序设计竞赛暨全国邀请赛 签到题9题