题解 商人

传送门

考虑对每个 \(z\) 求出收益 \(\geqslant z\) 的方案数,然后差分减去
对每个 \(z\),考虑枚举用了 \(x\) 个左括号
那么有 \(n-x\) 个右括号,最多有 \(k=n-x-z\) 个是可以浪费的
令选左括号为向上走,选右括号为向右走
那么就是从 \((0, 0)\)\((n-x, x)\),不能跨越 \(y=x-k-1\)
一番折线容斥后发现就是 \(\binom{n}{x}-\binom{n}{n-z+1}\)
那么每个 \(z\) 的答案就是 \(\sum\limits_{i=z}^{n-z}(\binom{n}{i}-\binom{n}{n-z+1})\)
发现后面一项与 \(x\) 无关,前面一项可以前缀和
那么复杂度 \(O(n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 1000010
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, typ;
ll pw[N];
const ll base=233, mod=998244353;
inline void md(ll&a, ll b) {a+=b; a=a>=mod?a-mod:a;}

namespace force{
	ll ans[N], sum;
	void solve() {
		int lim=1<<n;
		for (int s=0; s<lim; ++s) {
			int cnt=0, in=0;
			for (int i=0; i<n; ++i)
				if (s&(1<<i)) {if (in) --in, ++cnt;}
				else ++in;
			++ans[cnt];
		}
		if (typ&1) printf("%lld\n", ans[k]);
		else {
			for (int i=0; i<=n/2; ++i) sum=(sum+pw[i]*ans[i])%mod;
			printf("%lld\n", sum);
		}
	}
}

namespace task1{
	ll f[310][310][310], ans[N], sum;
	void solve() {
		// cout<<double(sizeof(f))/1000/1000<<endl;
		f[1][0][0]=1;
		for (int i=1; i<=n; ++i) {
			for (int j=0; j<=i; ++j) {
				for (int t=0; t<=i; ++t) if (f[i][j][t]) {
					md(f[i+1][j+1][t], f[i][j][t]);
					if (j) md(f[i+1][j-1][t+1], f[i][j][t]);
					else md(f[i+1][0][t], f[i][j][t]);
				}
			}
		}
		for (int j=0; j<=n; ++j)
			for (int t=0; t<=n; ++t) if (f[n+1][j][t])
				md(ans[t], f[n+1][j][t]);
		if (typ&1) printf("%lld\n", ans[k]);
		else {
			for (int i=0; i<=n/2; ++i) sum=(sum+pw[i]*ans[i])%mod;
			printf("%lld\n", sum);
		}
	}
}

namespace task{
	ll fac[N], inv[N], sum[N], ans[N], tem;
	inline ll C(int n, int k) {return fac[n]*inv[k]%mod*inv[n-k]%mod;}
	void solve() {
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<=n; ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<=n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<=n; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		for (int i=0; i<=n; ++i) sum[i]=(sum[max(i-1, 0)]+C(n, i))%mod;
		for (int i=0; i<=n; ++i) ans[i]=(((sum[n-i]-(i?sum[i-1]:0))-(n-2*i+1)*C(n, n+1-i))%mod+mod)%mod;
		for (int i=0; i<n; ++i) ans[i]=((ans[i]-ans[i+1])%mod+mod)%mod;
		if (typ&1) printf("%lld\n", ans[k]);
		else {
			for (int i=0; i<=n/2; ++i) tem=(tem+pw[i]*ans[i])%mod;
			printf("%lld\n", tem);
		}
	}
}

signed main()
{
	freopen("b.in", "r", stdin);
	freopen("b.out", "w", stdout);

	typ=read();
	n=read(); if (typ&1) k=read();
	pw[0]=1;
	for (int i=1; i<=n; ++i) pw[i]=pw[i-1]*base%mod;
	// force::solve();
	// task1::solve();
	task::solve();

	return 0;
}
posted @ 2022-05-09 20:56  Administrator-09  阅读(1)  评论(0编辑  收藏  举报