题解 [BJOI2019]勘破神机

发布时间:2022-06-27 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了题解 [BJOI2019]勘破神机脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Description

https://loj.ac/p/3090

Solution

(m=2)

设填满宽度为 (n) 的核心的方案数为 (f(n)) , 那么答案即为 (sumlimits_{i=l}^rbinom{f(i)}{k}) . 考虑求出 (f(n)) 的通项 . 不难发现最后两行只有两种可能的情况 1.

题解 [BJOI2019]勘破神机

2.

题解 [BJOI2019]勘破神机

两种情况的答案分别是 (f(n-1),f(n-2)), 那么就得到了递推式 (f(n)=f(n-1)+f(n-2)).

(f(x))(f) 数列的生成函数 . 那么有 (f(x)=xf(x)+x^2f(x)+1) (displaystyle f(x)=frac{1}{1-x-x^2}) 将分母因式分解 (displaystyle(1-x-x^2)=-(x-x_1)(x-x_2),x_1=frac{-1+sqrt5}2,x_2=frac{-1-sqrt5}2) (displaystyle f(x)=frac{-1}{(x-x_1)(x-x_2)}) 尝试将分母拆开 (displaystyle f(x)=frac{a}{x-x_1}+frac{b}{x-x_2}) 需要构造 (a,b) 满足 (a(x-x_2)+b(x-x_1)=-1) 解得 (begin{cases}a=-frac{sqrt5}{5}\b=frac{sqrt5}{5}end{cases}) (begin{aligned}f(x)&=frac{a}{x-x_1}+frac{b}{x-x_2}\&=frac{a}{x_1}frac{1}{frac{x}{x_1}-1}+frac{b}{x_2}frac{1}{frac{x}{x_2}-1}\&=-(frac{a}{x_1}frac{1}{1-frac{x}{x_1}}+frac{b}{x_2}frac{1}{1-frac{x}{x_2}})\&=-(frac{a}{x_1}sumlimits_i(frac{x}{x_1})^i+frac{b}{x_2}sumlimits_i(frac{x}{x_2})^i)end{aligned}) 那么 (displaystyle[x^n]f(x)=-(frac{a}{x_1}(frac{1}{x_1})^n+frac{b}{x_2}(frac{1}{x_2})^n)) 代入 (x_1,x_2,a,b), 得 (displaystyle[x^n]f(x)=frac{sqrt5}{5}(frac{1+sqrt5}{2})^{n+1}-frac{sqrt5}{5}(frac{1-sqrt5}{2})^{n+1}) 为了方便将 (f) 整体平移一下 , 计算答案时将 (l,r) 也平移即可 . (displaystyle[x^n]f(x)=frac{sqrt5}{5}(frac{1+sqrt5}{2})^n-frac{sqrt5}{5}(frac{1-sqrt5}{2})^n)(displaystyle A=frac{sqrt5}{5},B=-frac{sqrt5}{5},X=frac{1+sqrt5}{2},Y=frac{1-sqrt5}{2})(displaystyle[x^n]f(x)=AX^n+BY^n)

然后对答案式进行变形 (begin{aligned}&sumlimits_{n=l}^rbinom{f(n)}{k}\&=sumlimits_{n=l}^rfrac{f(n)^{underline k}}{k!}\&=frac{1}{k!}sumlimits_{n=l}^rsumlimits_{i=0}^k(-1)^{k-i}begin{bmatrix}k\iend{bmatrix}(AX^n+BY^n)^i\&=frac{1}{k!}sumlimits_{n=l}^rsumlimits_{i=0}^k(-1)^{k-i}begin{bmatrix}k\iend{bmatrix}sumlimits_{j=0}^ibinom ij(AX^n)^j(BY^n)^{i-j}\&=frac{1}{k!}sumlimits_{i=0}^k(-1)^{k-i}begin{bmatrix}k\iend{bmatrix}sumlimits_{j=0}^ibinom ijA^jB^{i-j}sumlimits_{n=l}^r(X^n)^j(Y^n)^{i-j}end{aligned}) 前面两个求和符号可以 (O(k^2)) 枚举 , 最后一个求和符号为等比数列求和 . (sqrt5) 可以通过把数域拓展为 (a+bsqrt5) 来处理 . 注意特判公比为 (1)

(m=3)

(m=2) 类似 , 先考虑求出通项 . 不难发现只有长度为偶数时才有解 , 那么设 (g(n)) 为填满宽度为 (2n) 的核心的方案数 . 最后的放置方案有三类 1.

题解 [BJOI2019]勘破神机

2.

题解 [BJOI2019]勘破神机

注意到这种填充可以无限延伸 , 即这种也被分到该类中

题解 [BJOI2019]勘破神机

3. 为 2 的镜像

这三种的方案数分别为 (g(n-1),sumlimits_{i<n}g(i),sumlimits_{i<n}g(i)) 那么得出递推式 (g(n)=g(n-1)+2sumlimits_{i<n}g(i))

写成生成函数就是 (g(x)=xg(x)+2sumlimits_{i=1}x^ig(x)+1) (displaystyle g(x)=xg(x)+frac{2x}{1-x}g(x)+1) (displaystyle g(x)=frac{1-x}{x^2-4x+1})

使用和 (m=2) 时完全相同的技术可以得到通项 (displaystyle[x^n]g(x)=frac{3-sqrt3}{6}(2-sqrt3)^n+frac{3+sqrt3}{6}(2+sqrt3)^n) 使用和 (m=2) 时完全相同的技术可以 (O(k^2)) 求出答案 .

Code
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
template<typename T=int>T read()
{
	T ret=0;bool f=0;char c=getchar();
	while(c>'9'||c<'0')f|=(c=='-'),c=getchar();
	while(c>='0'&&c<='9')ret=(ret<<3)+(ret<<1)+(c^48),c=getchar();
	return f?-ret:ret;
}
int T,m;
const int mod=998244353;
const int maxn=550;
namespace global
{
	int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=(ll)a*a%mod)if(b&1)ret=(ll)ret*a%mod;return ret;}
	struct modint
	{
		int val;
		int qmod(int x)const{return x>=mod?x-mod:x<0?x+mod:x;}
		modint(ll v=0){val=v%mod;}
		modint operator +(const modint&x)const{return qmod(val+x.val);}
		modint operator -(const modint&x)const{return qmod(val-x.val);}
		modint operator *(const modint&x)const{return (ll)val*x.val%mod;}
		modint operator /(const modint&x)const{return (ll)val*qpow(x.val,mod-2)%mod;}
	};
	modint fac[maxn],inv[maxn],s[maxn][maxn];
	void prework()
	{
		int n=510;
		fac[0]=1;for(int i=1;i<=n;i++)fac[i]=fac[i-1]*i;
		inv[0]=inv[1]=1;for(int i=2;i<=n;i++)inv[i]=inv[mod%i]*(mod-mod/i);
		for(int i=2;i<=n;i++)inv[i]=inv[i-1]*inv[i];
		s[0][0]=1;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)s[i][j]=s[i-1][j-1]+s[i-1][j]*(i-1);
	}
	modint C(int n,int m){return fac[n]*inv[m]*inv[n-m];}
}using global::C,global::prework,global::modint,global::s,global::inv;
namespace sub1
{
	struct Int
	{
		modint a,b;
		Int(modint aa=0,modint bb=0){a=aa;b=bb;}
		Int operator +(const Int &x)const{return {a+x.a,b+x.b};}
		Int operator -(const Int &x)const{return {a-x.a,b-x.b};}
		Int operator *(const Int &x)const{return {a*x.a+b*x.b*5,a*x.b+b*x.a};}
		Int operator *(const modint &x)const{return {a*x.val,b*x.val};}
		Int operator /(const Int &x)const{modint bas=x.a*x.a-x.b*x.b*5;return {(a*x.a-b*x.b*5)/bas,(b*x.a-a*x.b)/bas};}
	};
	Int qpow(Int a,ll b){Int ret(1,0);for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a;return ret;}
	const Int A(0,598946612),B(0,399297741),X(499122177,499122177),Y(499122177,499122176);
	int calc(ll l,ll r,int k)
	{
		int ret=0;
		for(int i=0;i<=k;i++)
		{
			Int sum(0,0);
			for(int j=0;j<=i;j++)
			{
				Int sum1(0,0);
				Int now=qpow(X,j)*qpow(Y,i-j);
				if(now.a.val==1&&now.b.val==0)sum1=Int(r-l+1,0);
				else sum1=(qpow(now,r+2)-qpow(now,l+1))/(now-(Int){1,0});
				sum=sum+sum1*C(i,j)*qpow(A,j)*qpow(B,i-j);
			}
			if((k-i)&1)ret=(ret-(ll)sum.a.val*s[k][i].val%mod+mod)%mod;
			else ret=(ret+(ll)sum.a.val*s[k][i].val%mod)%mod;
		}
		return (ll)ret*inv[k].val%mod*global::qpow((r-l+1)%mod,mod-2)%mod;
	}
}
namespace sub2
{
	struct Int
	{
		modint a,b;
		Int(modint aa=0,modint bb=0){a=aa;b=bb;}
		Int operator +(const Int &x)const{return {a+x.a,b+x.b};}
		Int operator -(const Int &x)const{return {a-x.a,b-x.b};}
		Int operator *(const Int &x)const{return {a*x.a+b*x.b*3,a*x.b+b*x.a};}
		Int operator *(const modint &x)const{return {a*x.val,b*x.val};}
		Int operator /(const Int &x)const{modint bas=x.a*x.a-x.b*x.b*3;return {(a*x.a-b*x.b*3)/bas,(b*x.a-a*x.b)/bas};}
	};
	Int qpow(Int a,ll b){Int ret(1,0);for(;b;b>>=1,a=a*a)if(b&1)ret=ret*a;return ret;}
	const Int A(499122177,831870294),B(499122177,166374059),X(2,998244352),Y(2,1);
	int calc(ll l,ll r,int k)
	{
		int len=(r-l+1)%mod;
		r=r/2;l=(l-1)/2+1;
		int ret=0;
		for(int i=0;i<=k;i++)
		{
			Int sum(0,0);
			for(int j=0;j<=i;j++)
			{
				Int sum1(0,0);
				Int now=qpow(X,j)*qpow(Y,i-j);
				if(now.a.val==1&&now.b.val==0)sum1=Int(r-l+1,0);
				else sum1=(qpow(now,r+1)-qpow(now,l))/(now-(Int){1,0});
				sum=sum+sum1*C(i,j)*qpow(A,j)*qpow(B,i-j);
			}
			if((k-i)&1)ret=(ret-(ll)sum.a.val*s[k][i].val%mod+mod)%mod;
			else ret=(ret+(ll)sum.a.val*s[k][i].val%mod)%mod;
		}
		return (ll)ret*inv[k].val%mod*global::qpow(len,mod-2)%mod;
	}
}
int main()
{
	T=read();m=read();
	prework();
	while(T--)
	{
		ll l=read<ll>(),r=read<ll>();int k=read();
		if(m==2)printf("%dn",sub1::calc(l,r,k));
		else printf("%dn",sub2::calc(l,r,k));
	}
	return 0;
}

脚本宝典总结

以上是脚本宝典为你收集整理的题解 [BJOI2019]勘破神机全部内容,希望文章能够帮你解决题解 [BJOI2019]勘破神机所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: