小R打怪兽

题目描述

小R打怪兽_第1张图片

推式子

首先我们设 Bi=max(ADi,1)
mi=1XjHjYj[nj=1[HjBji]k]
这让我们很不好搞,但是我们可以容斥,枚举若干个,然后要求这些一定要击败,其余则随意。容斥系数见博客置顶文章容斥的原理及广义应用中的方法求出。接下来我们用f表示容斥系数。
mi=1Sf(|S|)XjHjYjΠjS[HjBji]
mi=1Sf(|S|)Πnj=1([jS](YjXj+1)+[jS]YjHj=Xj[HjBji])
mi=1Sf(|S|)Πnj=1([jS](YjXj+1)+[jS]max(min(Yj,Bji)Xj+1),0))
观察最后那个又有max又有min的东西,现在可以注意到对于每个j可以找到两个i作为分界点,在不同的i值域区间里最后那个式子会有不同的取值。
我们把所有关键点提取出来排序,然后现在关键点之间的区间里每个j影响固定了,我们考虑怎么计算答案。
我们设ff[i,j,k]表示考虑到第i个怪物,目前往S里选了j个怪物(这一维方便我们最后乘上容斥系数),然后有k个过了第一个分界点但是没过第二个分界点的(此时这样的怪物贡献是 BjiXj+1 ,可以把它给展开掉),我们选择了k个 Bji (当然我们还没有乘上i)。这一维我们最后需要给它乘一个自然数幂和。

#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=50+10,mo=1000000007;
int f[maxn],ff[maxn][maxn][maxn],c[maxn][maxn],su[maxn][maxn],S[maxn],g[maxn],gg[maxn];
int x[maxn],y[maxn],d[maxn],b[maxn];
struct dong{
    int x,y;
    friend bool operator <(dong a,dong b){
        return a.xx||a.x==b.x&&a.y>b.y;
    }
} p[maxn*2];
bool bz[maxn],pd[maxn];
int i,j,k,l,t,n,m,q,a,tot,top,ans;
void getS(int n,int m){
    int i,j,k,t;
    if (n<0){
        fo(i,0,m) S[i]=0;
        return;
    }
    S[0]=n;
    fo(i,1,m){
        t=1;
        fd(j,n+1,n-i+1)
            if (j%(i+1)==0) t=(ll)t*(j/(i+1))%mo;else t=(ll)t*j%mo;
        fo(j,0,i-1){
            k=(ll)su[i][j]*S[j]%mo;
            if ((i+j)%2==0) (t-=k)%=mo;else (t+=k)%=mo;
        }
        S[i]=t;
    }
}
void work(int l,int r){
    int i,j,k,t;
    fo(i,0,n)
        fo(j,0,n)
            fo(k,0,n)
                ff[i][j][k]=0;
    ff[0][0][0]=1;
    fo(i,0,n-1)
        fo(j,0,i)
            fo(k,0,j)
                if (ff[i][j][k]){
                    (ff[i+1][j][k]+=(ll)ff[i][j][k]*(y[i+1]-x[i+1]+1)%mo)%=mo;
                    if (pd[i+1]){
                        if (bz[i+1]) (ff[i+1][j+1][k]+=(ll)ff[i][j][k]*(y[i+1]-x[i+1]+1)%mo)%=mo;
                        else{
                            (ff[i+1][j+1][k]+=(ll)ff[i][j][k]*(1-x[i+1])%mo)%=mo;
                            (ff[i+1][j+1][k+1]+=(ll)ff[i][j][k]*b[i+1]%mo)%=mo;
                        }
                    }
                }
    getS(l-1,n);
    fo(i,0,n) g[i]=S[i];
    getS(r,n);
    fo(i,0,n) gg[i]=S[i];
    fo(j,0,n)
        fo(k,0,j)
            (ans+=(ll)ff[n][j][k]*f[j]%mo*(gg[k]-g[k])%mo)%=mo;
}
int main(){

    scanf("%d%d%d%d",&n,&m,&q,&a);
    fo(i,1,n){
        scanf("%d%d%d",&d[i],&x[i],&y[i]);
        b[i]=max(1,a-d[i]);
    }
    c[0][0]=1;
    su[0][0]=1;
    fo(i,1,n){
        c[i][0]=1;
        fo(j,1,i){
            c[i][j]=(c[i-1][j]+c[i-1][j-1])%mo;
            su[i][j]=(su[i-1][j-1]+(ll)su[i-1][j]*(i-1)%mo)%mo;
        }
    }
    fo(i,0,n){
        t=0;
        fo(j,0,i-1) (t+=(ll)c[i][j]*f[j]%mo)%=mo;
        if (i>=q) f[i]=1-t;else f[i]=-t;
    }
    fo(i,1,n){
        t=x[i]/b[i];
        if (x[i]%b[i]) t++;
        p[++top].x=t;
        p[top].y=i;
        t=(y[i]+1)/b[i];
        if ((y[i]+1)%b[i]) t++;
        p[++top].x=t;
        p[top].y=i;
    }
    p[++top].x=m;
    p[++top].x=1;
    p[top].y=-1;
    sort(p+1,p+top+1);
    fo(i,1,top){
        if (p[i].y==0){
            work(m,m);
            break;
        }
        if (p[i].y>0){
            j=p[i].y;
            if (!pd[j]) pd[j]=1;else bz[j]=1;
        }
        if (p[i].x>=1&&p[i].x1].x) work(p[i].x,p[i+1].x-1);
    }
    (ans+=mo)%=mo;
    printf("%d\n",ans);
}

你可能感兴趣的:(一般动规与递推,容斥原理)