SSZX集训 Contest 20210203 递推,最小生成树,矩阵快速幂,染色

题目已存档至百度网盘

前言: 还行,就是有人AK,令人不爽


方阵(matrix)

标程是记录每行每列的染色时间,我的做法是从指令最后往前处理,染色过的就不能再染了.时间复杂度为 O ( n + n m + q ) O(n+nm+q) O(n+nm+q),可以通过.

/*
从后往前排,排过的就锁住不能再排了

问题:1、快写居然出问题了 
*/
#include <bits/stdc++.h>

using namespace std;
const int MAXQ=1e6+5,MAXN=1e3+5;
int n,m,q,x[MAXQ],y[MAXQ],z[MAXQ],tot;
bool vish[MAXN],visl[MAXN],vis_map[MAXN][MAXN];
int ans[MAXN][MAXN];

inline int read()
{
	int s=1,x=0;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')s=-1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
	return s*x;
}

//void write(int x)
//{
//	if(x<0)
//	{
//		x=-x;
//		putchar('-');
//	}
//	else if(x>9)
//	{
//		write(x/10);
//	}
//	putchar();
//}

int main()
{
	freopen("matrix.in","r",stdin);
	freopen("matrix.out","w",stdout);
	
	n=read();
	m=read();
	q=read();
	const int tot_map=n*m;
	
	for(int i=1;i<=q;i++)
	{
		x[i]=read();y[i]=read();z[i]=read();
	}
	for(int i=q;i>=1;i--)
	{
		int h=y[i];
		if(x[i]==1&&vish[h]==false)
		{
			for(int j=1;j<=m;j++)
			{
				if(vis_map[h][j]==false)
				{
					ans[h][j]=z[i];
					vis_map[h][j]=true;
					tot++;
				}
			}
			vish[h]=true;
		}
		if(x[i]==2&&visl[h]==false)
		{
			for(int j=1;j<=n;j++)
			{
				if(vis_map[j][h]==false)
				{
					ans[j][h]=z[i];
					vis_map[j][h]=true;
					tot++;
				}
			}
			visl[h]=true;
		}
		if(tot==tot_map)
			break;
	}
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			printf("%d",ans[i][j]);
			putchar(' ');
		}
		putchar('
');
	}
	
	return 0;
}

另外,此题的write函数居然出锅了,应该这么写:

void write(int x)
{
	if(x<0)
	{
		x=-x;
		putchar('-');
	}
	else if(x>9)
	{
		write(x/10);
	}
	putchar(x%10+48);
}

putchar(x%10+48)不是putchar(`x%10+48`)

坐标系(coordinate)

此题为Openjudge那道奶牛散步数据加强版,递推经典题呀.递推关系式为 f n = 2 f n − 1 + f n − 2 f_n=2f_{n-1}+f_{n-2} fn=2fn1+fn2.但今天做的时候显然忘记了,于是先搞了一个dfs把前几项算了出来.又因为前几天在接受数学的熏陶,弄了很久的差分表,结果发现根本弄不出来,直接吐血.(其实显然弄不出来,因为答案并不能被表示为多项式)

但好就好在,偶从差分表中看出了规律,最后列出了递推关系式.

另外,这道题数据范围过大,考虑优化.

方案一: 打表

在本机测试了用时:

1000000000
999999966
Use Time:16.217000

也就是说,我们将复杂度优化到 1 0 7 10^7 107即可.

我 们 已 经 知 道 了 f n = 2 f n − 1 + f n − 2 , 那 么 显 然 , 要 知 道 f n , 只 用 知 道 f n − 1 和 f n − 2 . 选 择 打 出 所 有 f n 与 f n + 1 ( n = 1 0 7 k , k 为 正 整 数 ) 我们已经知道了f_n=2f_{n-1}+f_{n-2},那么显然,要知道f_n,只用知道f_{n-1}和f_{n-2}.选择打出所有f_n与f_{n+1}(n=10^7k,k为正整数) fn=2fn1+fn2,,fn,fn1fn2.fnfn+1(n=107k,k)

具体操作如下代码,也是考试时写出来的.打表的数据是用原本的未优化代码生成的.

#include <bits/stdc++.h>
#define ll long long

using namespace std;
ll n;
ll biao1[1005]={0,627935421,438953224,542068249,329814112,560895073,119554882,817838024,413683704,457693522,548686427,625090930,854797397,507897869,61876493,38377219,305397032,834552550,86754567,509991039,595114395,406847212,670491536,432878314,135680620,898309326,728242939,198112061,177816349,19047210,455754392,852650532,521176598,71125034,245305647,837039919,188113267,56598060,432474979,432717386,87865010,771920945,438742654,288408342,246724129,896686551,339943192,339062029,917394372,746339567,880572807,739796257,59753287,776287897,225152152,836502060,948930900,475746791,722277745,851272656,790561977,985377610,885700761,132420780,835281543,520522277,705708011,107967744,357214655,287632826,452485219,234406704,490642737,105936544,662318372,10700633,44184524,425184700,853280967,501062760,425337376,984713729,821083793,448257541,299730624,956477347,53544543,258784453,686484973,12946211,133711137,828167667,821810848,728440912,992782964,810060630,81297710,592494925,333385653,68086064,999999966};
ll biao2[1005]={0,316019740,372654023,224763656,22469312,782122008,34120220,931864090,425814224,323613731,426904732,655133268,419960676,600143856,636422754,404303050,514440356,364914981,228761950,38777592,133257557,122058434,66188449,284201981,606451036,708146069,58038914,491958600,718356299,472529774,855728576,454092882,3075198,128033925,672313652,274523182,685346016,965382417,79327031,70919624,314176084,524093558,507000754,423517629,401454042,306672104,839594331,294033500,29439574,960708835,59713600,296223267,981986607,148291544,877858011,326733601,500718454,694404815,412489057,164309652,746610433,220032885,261585106,940108177,802956593,46695727,852179533,782419693,57729179,975765453,190151629,400743276,947414172,856017108,746680441,337348962,303616399,286766519,671925310,423986587,856516568,213870031,317318877,493679984,182995823,98269674,305866735,16514990,809398153,525848172,231896493,533455685,956438514,294996456,409710864,32400151,771974784,207954764,741176549,835969528};

int main()
{
//	freopen("coordinate.in","r",stdin);
//	freopen("coordinate.out","w",stdout);
	
	register long long f[3]={3,7};
	register long long mod=1e9+7;
	cin>>n;
	if(n<=2)
	{
		cout<<f[n-1]<<endl;
		return 0;
	}
	
	if(n<=10000000)
	{
		for(register int i=3;i<=n;i++)
		{
			f[2]=(2*f[1]+f[0])%mod;
			f[0]=f[1],f[1]=f[2];
		}
		cout<<f[2]<<endl;
	}
	else
	{
		int k=n/10000000;
		n%=10000000;
		f[0]=biao1[k];
		f[1]=biao2[k];
		if(n<=1)
		{
			cout<<f[n]<<endl;
			return 0;
		}
		for(register int i=2;i<=n;i++)
		{
			f[2]=(2*f[1]+f[0])%mod;
			f[0]=f[1],f[1]=f[2];
		}
		cout<<f[2]<<endl;
	}
	
	
	return 0;
}

方案二: 矩阵快速幂

递推关系式的优化都可以用到矩阵快速幂,前几天讲课时也提到过,我已经写了一篇新的博客来介绍.

原文地址:https://www.cnblogs.com/huaruoji/p/14425563.html