码迷,mamicode.com
首页 > 其他好文 > 详细

CF1204E Natasha, Sasha and the Prefix Sums

时间:2019-11-06 22:31:57      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:坐标   组合   math   pre   复杂   问题   ++i   def   The   

题意

\(n\)个1和\(m\)个0,定义一个01串的权值为它所有前缀和的最大值(包括0),求可以组成的所有不同串的权值和,答案对998244853取模

思路

由于数据较小,本题有个\(O(n^2)\)比较复杂的DP做法,自行百度。。。

实际上本题用数学规律可以\(O(n)\)

\(f_i\)表示权值为\(i\)的01串数量,直接求不容易,再设\(g_i\)为权值至少\(i\)的01串数量,那么\(f_i=g_i-g_{i+1}\)

利用求卡特兰数列的一种方法:将01串看做从坐标系\((0,0)\)\((m,n)\)的一条路径,即纵轴为1,横轴为0
此时\(g_i\)表示直线\(y=x+i\),求经过它的路径;类比卡特兰数列,我们将\((0,0)\)做个对称点变成\((-i,i)\),从\((-i,i)\)\((m,n)\)的所有路径均为经过\(y=x+i\)的路径,即\(g_i=C(n+m,n-i)\)

预处理个组合数即可求出所有的\(g\),从而求出答案

然后写出来样例都过不了

问题出在上面的做对称点,为什么要做对称点?因为做了对称点后可以保证每条路径都过直线\(y=x+i\),但如果\((0,0)\)\((n,m)\)本来就必过\(y=x+i\)就不能做对称点了

Code

#include<bits/stdc++.h>
#define N 4005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
const ll mod = 998244853;
int n,m;
ll inv[N],jc[N];

template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
ll quickpow(ll a,ll b)
{
    ll ret=1;
    while(b)
    {
        if(b&1) ret=ret*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ret;
}
void init(int maxn)
{
    jc[0]=1; for(int i=1;i<=maxn;++i) jc[i]=jc[i-1]*i%mod;
    inv[maxn]=quickpow(jc[maxn],mod-2);
    for(int i=maxn-1;i>=0;--i) inv[i]=inv[i+1]*(i+1)%mod;
}
ll C(int n,int m) { return n>=m ? jc[n]*inv[m]%mod*inv[n-m]%mod : 0; }
ll g(int i) { return (m>n-i) ? C(n+m,n-i) : C(n+m,n); }
int main()
{
    read(n);read(m);
    init(N-1);
    ll ans=0;
    for(int i=0;i<=n;++i) ans+=(g(i)-g(i+1))%mod*i%mod;
    cout<<(ans%mod+mod)%mod<<endl;
    return 0;
}

CF1204E Natasha, Sasha and the Prefix Sums

标签:坐标   组合   math   pre   复杂   问题   ++i   def   The   

原文地址:https://www.cnblogs.com/Chtholly/p/11808918.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!