题解 商人
考虑对每个 \(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;
}