【51nod】 1229 序列求和 V2

题解:需要先推递推公式,发现递推后,直接O(k^2)暴力找就行,注意当r=1的时候,分母为0,需要特判,使用fold筛处理。

题目链接

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const int maxn = 2e3 + 10;
const ll mod = 1e9 + 7;
ll s[maxn], rr[maxn];
ll fac[maxn], inv[maxn];
ll pow(ll a, ll p, ll MOD)	//p=(mod-2)用来求逆元 
{
	a = a % MOD;
	ll ans = 1;
	while (p)
	{
		if (p & 1)
		{
			ans = (ans*a) % MOD;
		}
		a = (a*a) % MOD;
		p >>= 1;
	}
	return ans;
}
ll C(int n, int m)
{
	return fac[n] * inv[m] % mod * inv[n - m] % mod;
}
void init()
{
	fac[0] = inv[0] = 1;
	for (int i = 1; i < maxn; i++)
	{
		fac[i] = fac[i - 1] * i % mod;
		inv[i] = pow(fac[i], mod - 2, mod);
	}
}
//fold筛 
int pv[maxn]; //前几项, 前面无效值用0占位
int st = 1, ed = maxn;           //使用上面数组下标为[st,ed]的数据
ll fac_1[maxn + 5], inv_1[maxn + 5], facinv[maxn + 5];
ll pre[maxn + 5], saf[maxn + 5];
void init_fold()
{
	fac_1[0] = inv_1[0] = facinv[0] = 1;
	fac_1[1] = inv_1[1] = facinv[1] = 1;
	for (int i = 2; i < ed + 3; ++i)
	{
		fac_1[i] = fac_1[i - 1] * i%mod;
		inv_1[i] = mod - (mod / i * inv_1[mod%i] % mod);
		facinv[i] = facinv[i - 1] * inv_1[i] % mod;
	}
}
ll cal(ll x0)
{
	int n = ed - st;
	x0 = ((x0%mod) + mod) % mod;
	pre[0] = ((x0 - st) % mod + mod) % mod;
	saf[n] = ((x0 - st - n) % mod + mod) % mod;
	for (int i = 1; i <= n; ++i)
	{
		pre[i] = ((pre[i - 1] * (x0 - st - i)) % mod + mod) % mod;
		saf[n - i] = ((saf[n - i + 1] * (x0 - st - n + i)) % mod + mod) % mod;
	}
	ll res = 0;
	for (int i = 0; i <= n; ++i)
	{
		ll fz = 1;
		if (i != 0)fz = fz * pre[i - 1] % mod;
		if (i != n)fz = fz * saf[i + 1] % mod;
		ll fm = facinv[i] * facinv[n - i] % mod;
		if ((n - i) & 1)fm = mod - fm;
		(res += pv[i + st] * (fz*fm%mod) % mod) %= mod;
	}
	return res;
}
int main()
{
	int t;
	cin >> t;
	ll n, k, r;
	init();												//打表出组合数 
	while (t--)
	{
		cin >> n >> k >> r;
		memset(s, 0, sizeof(s));
		memset(rr, 0, sizeof(rr));
		if (r != 1)//当r不等于1的时候 
		{
			ll inv_ = pow(r - 1, mod - 2, mod);
			ll temp_r = pow(r, n + 1, mod);
			s[0] = ((pow(r, n + 1, mod) - r % mod + mod) % mod*inv_ + mod) % mod;	//求s0,注意r的范围为long long ,直接减会变成很大的负数,需要先取模 
			for (int i = 1; i <= k; i++)
				rr[i] = pow(n, i, mod);
			for (int i = 1; i <= k; i++)
			{
				s[i] = ((temp_r*rr[i] + mod) % mod - r % mod + mod) % mod;
				for (int j = 0; j < i; j++)
				{
					s[i] = (s[i] + C(i, j)*(s[j] - r % mod) % mod*pow(-1, i - j) + mod);
					s[i] = s[i] % mod;
				}
				s[i] = (s[i] * inv_ + mod) % mod;
			}
			cout << s[k] << endl;
		}
		else//当r等于1的时候,因为分母不能为0,所以需要特殊计算,使用fold即可 
		{
			memset(pv, 0, sizeof(pv));
			for (int i = 1; i <= k+2; i++)
			{
				pv[i] = pow(i, k, mod) + pv[i - 1] % mod;
			}
			ed = k + 2;
			init_fold();
			cout << cal(n) << endl;
		}
	}
	return 0;
}
发布了119 篇原创文章 · 获赞 20 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/qq_40727946/article/details/94666600