1198 51nod 字符串的数量V3

本文介绍了两种C++代码实现,一种是普通版本,涉及多项式运算、模运算和组合数计算;另一种是高效版本,使用了位操作和快速傅立叶变换(FFT)技巧,以解决特定数学问题。
摘要由CSDN通过智能技术生成

51nod难题系列新代码来啦

普通代码:

#include<cstdio>
typedef long long ll;
const int MOD = int(1E9) + 7;
const int MSIZE = 64;
int pow_mod(int b, int p) {
	int ret = 1;
	while( p ) {
		if( p & 1 ) ret = 1LL*ret*b%MOD;
		b = 1LL*b*b%MOD;
		p >>= 1;
	}
	return ret;
}
int len;
struct poly{
	int k[2*MSIZE + 5];
	poly() {for(int i=0;i<=2*MSIZE;i++) k[i] = 0;}
	int get_val(int x) {
		int ret = 0;
		for(int i=len;i>=0;i--)
			ret = (1LL*ret*x%MOD + k[i])%MOD;
		return ret;
	}
	friend poly operator +(poly A, poly B) {
		poly C;
		for(int i=0;i<MSIZE;i++)
			C.k[i] = (A.k[i] + B.k[i])%MOD;
		return C;
	}
	friend poly operator -(poly A, poly B) {
		poly C;
		for(int i=0;i<MSIZE;i++)
			C.k[i] = (A.k[i] + MOD - B.k[i])%MOD;
		return C;
	}
	friend poly operator *(int k, poly B) {
		poly C;
		for(int i=0;i<MSIZE;i++)
			C.k[i] = 1LL*k*B.k[i]%MOD;
		return C;
	}
	friend poly mul_mod(poly A, poly B, poly C) {
		poly D;
		for(int i=0;i<=2*len;i++)
			for(int j=0;j<=i;j++)
				D.k[i] = (D.k[i] + 1LL*A.k[j]*B.k[i-j]%MOD)%MOD;
		for(int i=2*len;i>=len;i--) {
			for(int j=0;j<=len;j++)
				D.k[i-len+j] = (D.k[i-len+j] + MOD - 1LL*D.k[i]*C.k[j]%MOD)%MOD;
		}
		return D;
	}
	void debug() {
		for(int i=0;i<2*MSIZE;i++)
			printf("%d ", k[i]);
		puts("");
	}
}pw[MSIZE + 5], a[MSIZE + 5];
int comb[MSIZE + 5][MSIZE + 5];
void init() {
	for(int i=0;i<MSIZE;i++) {
		comb[i][0] = 1;
		for(int j=1;j<=i;j++)
			comb[i][j] = (comb[i-1][j] + comb[i-1][j-1])%MOD;
	}
	for(int i=0;i<MSIZE;i++) {
		for(int j=0;j<=i+1;j++)
			pw[i].k[j] = comb[i+1][j];
		for(int j=0;j<i;j++)
			pw[i] = (pw[i] - comb[i+1][j]*pw[j]);
		pw[i] = 1LL*pow_mod(i+1, MOD-2)*pw[i];
	}
	for(int i=0;i<MSIZE;i++)
		for(int j=0;j<=i+1;j++)
			for(int k=0;k<=j;k++)
				a[i].k[k] = (a[i].k[k] + 1LL*pw[i].k[j]*(1LL*comb[j][k]*(1LL*pow_mod(2, k)*pow_mod(MOD-1, j-k)%MOD)%MOD)%MOD)%MOD;
}
int get_pw(ll x, int k) {return pw[k].get_val(x%MOD);}
int get_pw(ll l, ll r, int k) {return (get_pw(r, k) + MOD - get_pw(l - 1, k))%MOD;}
int get_val(poly A, ll l, ll r) {
	int ret = 0;
	for(int i=0;i<len;i++)
		ret = (ret + 1LL*get_pw(l, r, i)*A.k[i]%MOD)%MOD;
	return ret;
}
poly trans(poly A, ll r) {
	poly B; B.k[0] = get_val(A, 0, r);
	for(int i=0;i<len;i++)
		B = B - A.k[i]*a[i];
	return B;
}
poly get_M(ll n) {
	poly A, B, M; B.k[0] = M.k[len] = 1;
	for(int i=0;i<len;i++,n/=2){
		int sA = get_val(A, 1, n/2), sB = get_val(B, n/2 + 1, n);
		M.k[len-i-1] = (MOD - (sA + sB)%MOD)%MOD;
		A = trans(A, n/2), A.k[0] = (A.k[0] + sB)%MOD;
		B = trans(B, n);
	}
	return M;
}
poly p_pow(poly M, ll p) {
	poly ret, b; b.k[1] = 1, ret.k[0] = 1;
	while( p ) {
		if( p & 1 ) ret = mul_mod(ret, b, M);
		b = mul_mod(b, b, M);
		p >>= 1;
	}
	return ret;
}
int solve(ll n, ll m) {
	ll tmp = n; for(len = 0; tmp; len++, tmp /= 2);
	return p_pow(get_M(n), m+len-1).k[len-1];
}
int main() {
	init(); int T; scanf("%d", &T);
	for(int i=1;i<=T;i++) {
		ll n, m; scanf("%lld%lld", &n, &m);
		printf("%d\n", solve(n, m));
	}
}

高效代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long s64;
#define rep(i,l,r) for(int i=l;i<=r;++i)
#define per(i,r,l) for(int i=r;i>=l;--i)
const int N=1e6+5,L=61,D=1e9+7;
s64 mi(s64 x,int y=D-2)
{
	s64 ans=1;
	while(y)
	{
		if(y&1)ans=ans*x%D;
		x=x*x%D;y>>=1;
	}
	return ans;
}
s64 w[L],dp[L];
s64 x[L],ans[L];

void mul(s64 a[],s64 b[])
{
	static s64 tmp[L*2];
	memset(tmp,0,sizeof(tmp));
	rep(i,0,L-1)
	rep(j,0,L-1)(tmp[i+j]+=a[i]*b[j])%=D;
	per(i,2*L-2,L)
	{
		s64 x=tmp[i];
		rep(j,1,L-1)(tmp[i-j]+=x*w[j])%=D;
	}
	memcpy(a,tmp,sizeof(x));
}

namespace GET_W
{ 
s64 w[L][L],dp[L];
void trans(int i)
{
	per(j,i,0)
	{
		s64 ans=0;
		rep(k,0,j)(ans+=dp[k]*w[i-k][j-k])%=D;
		dp[j]=ans; 
	}
}
void init()
{
	rep(i,0,L-1)
	{
		w[i][i]=1;
		rep(j,0,i-1)
		{
			s64 ans=0;
			rep(k,0,j)(ans+=w[i-1][k]*w[i-1-k][j-k])%=D;
			w[i][j]=ans;
		}
	}
}
void work(s64 n)
{
	n*=2;
	int i=0;
	while(!((n>>i)&1))++i;
	memcpy(dp,w[i],sizeof(dp));
	while(++i<L)
	if((n>>i)&1)trans(i);
	rep(i,0,L-1)::w[i]+=dp[i]; 
}
}; 
 
void work()
{
	s64 n,m;
	cin>>n>>m;
	
	memset(w,0,sizeof(w));
	GET_W::work(n/2);
	rep(i,0,L-1)w[i]=-w[i];
	GET_W::work(n);
	
	dp[0]=1;
	rep(i,1,L-1)
	{
		dp[i]=0;
		rep(j,0,i-1)(dp[i]+=dp[j]*w[i-j])%=D;
	}
	memset(x,0,sizeof(x));
	x[1]=1;
	--m;
	memcpy(ans,x,sizeof(ans));
	while(m)
	{
		if(m&1)mul(ans,x);
		mul(x,x);m>>=1;
	}
	s64 Ans=0;
	rep(i,0,L-1)(Ans+=ans[i]*dp[i])%=D;
	printf("%d\n",int((Ans%D+D)%D));
}

int main()
{
#ifdef kcz
	freopen("1.in","r",stdin);
#endif
	GET_W::init();
	int tt;
	cin>>tt;
	while(tt--)work();
}

喜欢就给个赞吧(记得关注)

  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值