8.25总结

A.幸福

因为n的数据范围为\(10^{18}\),所以O(n)和O(\(\sqrt{n}\))的做法是不行的,我就考虑这道题可能是结论题能够用公式O(1)完成。在考场上打表找规律找了好久,我都没找到规律,最后写了O(n)的做法,得到70pts。但这道题其实没有O(1)的公式。

以下是这道题的真实做法。因为可以推出&F_{n}=F_{n-1}+F{n-2}+f_{n}&,且\(n\leq 10^{18}\),所以我们考虑用矩阵快速幂来求\(F_{n}\)的前缀和。

设计矩阵为:
\(\begin{bmatrix}1&1&1&1&0\\1&0&0&0&0\\0&0&1&1&0 \\0&0&1&0&0 \\1&1&1&1&1 \end{bmatrix}\)

答案矩阵为:
\(\begin{bmatrix}F_{n}&F_{n-1}&f_{n}&f_{n-1}&S_{n}\end{bmatrix}\)\(S_{n}=\sum_{i=0}^{n}{F_{i}}\)

矩阵乘法核心代码:

AC Code
void multi(ll c[][N],ll a[][N],ll b[][N])
{
	ll tmp[N][N]={0};
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=5;j++)
		{
			for(int k=1;k<=5;k++)
			{
				tmp[i][j]=(tmp[i][j]+a[i][k]%mod*b[k][j]%mod)%mod;
			}
		}
	}
	for(int i=1;i<=5;i++)
	{
		for(int j=1;j<=5;j++)
		{
			c[i][j]=tmp[i][j]%mod;
		}
	}
}

void qow(ll x)
{
	ll res[N][N]={0};
	ll d[N][N]={0};
	d[1][1]=d[1][2]=d[1][3]=d[1][4]=1;
	d[2][1]=1;
	d[3][3]=d[3][4]=1;
	d[4][3]=1;
	d[5][1]=d[5][2]=d[5][3]=d[5][4]=d[5][5]=1;
	for(int i=1;i<=5;i++)res[i][i]=1;
	while(x)
	{
		if(x&1)multi(res,res,d);
		multi(d,d,d);x>>=1;
	}
	memset(d,0,sizeof d);
	d[1][1]=2;
	d[2][1]=1;
	d[3][1]=1;
	d[4][1]=1;
	d[5][1]=3;
	multi(d,res,d);
	printf("%lld\n",d[5][1]%mod);
}

要点:

  1. 你是否开了long long
  2. qow函数中的x你是否开了long long
  3. qow函数中的res和d数组是否清零
  4. 如果以上都对,检查进行矩阵乘法的两个矩阵是否写反
  5. 如果以上还是对的,那基本上就是公式推错了

事实给了我惨痛的教训,一定要清零,卡了我将近两个小时才发现问题。

B.奇怪的道路

吸取昨天的教训,在看到\(k\leq 8\)时,我就猜到要用状压DP来解决,但完全不知道如何设计状态啊,预计10pts,事实上0pts。

因为是无向图,我们可以只考虑i与前k个点的连边。因为k很小,我们可以把前k个点的奇偶性变成二进制。

设计状态:\(f_{i,j,s,p}\)表示第i个点,已经连了j条边,前k个点奇偶性为s,且只连了(i-k)~(i-p-1)的点的方案数

转移方程:

\[f_{i,j,s,p-1}+=f_{i,j,s,p} \]

\[if(i>p)f_{i,j+1,s\oplus 1\oplus 2^{p},p}+=f_{i,j,s,p} \]

\[if(!(s&(2^k)))f_{i+1,j,s*2,min(i,k)}+=f_{i,j,s,0} \]

初始状态:\(f_{1,0,0,0}=1\)
目标状态:\(f_{n,m,0,0}\)

AC Code
#include<bits/stdc++.h>
using namespace std;
const int mod=1e9+7;
int n,m,k;
int f[35][35][1025][35];

int main()
{
	cin>>n>>m>>k;
	f[1][0][0][0]=1;
	for(int i=1;i<=n;i++)
	{
		for(int j=0;j<=m;j++)
		{
			for(int s=0;s<(1<<(k+1));s++)
			{
				for(int p=min(i-1,k);p;p--)
				{
					(f[i][j][s][p-1]+=f[i][j][s][p])%=mod;
					if(i>p)(f[i][j+1][s^1^(1<<p)][p]+=f[i][j][s][p])%=mod;
				}
				if(!(s&(1<<k)))
				{
					(f[i+1][j][s<<1][min(i,k)]+=f[i][j][s][0])%=mod;
				}
			}
		}
	}
	cout<<f[n][m][0][0]<<endl;
	return 0;
}
posted @ 2022-08-25 21:34  两只风小鱼  阅读(20)  评论(0)    收藏  举报