NOI2018湖北省队集训Day3 T1 贪婪人

题面:
这里写图片描述


得分情况:
爆零。。。


正解:
我们用dp[n][m][w]表示在n*m的网格中,贪心路径权值为w的方案数,转移时枚举向右和向下,时间复杂度 O ( h w s 2 ) ,能过70%的数据。
我们首先可以通过维护前缀和去掉一个s,将复杂度降为 O ( h w s ) ,然后你还是只能过70%的点。
我们又发现,每次在不是图的右边界的位置向下走至少会对答案作出1的贡献(如果下面格子的权值为0必定会向右走),所以当走了s步之后必然会来到图的最右边,及经过点(s+1,w),所以我们只需要对s*w的格子做dp,其他的直接转移即可,总复杂度为 O ( w s 2 ) ,可以通过所有数据。


代码:

#include <bits/stdc++.h>
using namespace std;

const int mod=10007,maxn=3000,maxs=110;
int f1[maxn*2][maxs],f2[maxn*2][maxs],f3[maxn*2][maxs];
int fact[maxn<<3],invfact[maxn<<3];


int modpow(int x,int y)
{
    int nowans=1;
    while(y>0)
    {
        if(y%2==1) nowans=(nowans*x)%mod;
        x=(x*x)%mod;
        y/=2;
    }
    return nowans;
}

int calcu(int n,int k)
{
    int p=fact[n];
    p=(p*invfact[k])%mod;
    p=(p*invfact[n-k])%mod;
    return p;
}

int sum(int horz,int vert,int forced,int s)
{
    int nowans = 0;
    for (int a=0; a<=s; a++) {
        for (int b=0; a+b<=s; b++) {
            int c = s - b - a;

            int p = f1[horz][a];
            p *= f2[vert][b];
            p %= mod;
            p *= f3[forced][c];
            p%=mod;

            nowans += p;
            nowans%=mod;
        }
    }
    return nowans;
}

int h,w,s,ans;

int main()
{
    scanf("%d%d%d",&h,&w,&s);
    f1[0][0]=f2[0][0]=f3[0][0]=1;
    for(int i=1;i<=h+w+1;i++)
        for(int num=0;num<=s;num++)
        {
            f1[i][num]=f2[i][num]=f3[i][num]=0;
            for(int x=0;x<=num;x++)
            {
                f1[i][num]+=f1[i-1][num-x]*(x+1);
                f2[i][num]+=f2[i-1][num-x]*x;
                f3[i][num]+=f3[i-1][num-x];
            }
            f1[i][num]%=mod;
            f2[i][num]%=mod;
            f3[i][num]%=mod;
        }

    if(min(w,h)==1) { printf("%d\n",f3[w*h-1][s]);return 0; }

    fact[0]=1;
    invfact[0]=1;
    for(int i=1;i<=w+h+1;i++)
    {
        fact[i]=(fact[i-1]*i)%mod;
        invfact[i]=modpow(fact[i],mod-2);
    }

    for(int i=0;i<=w-2;i++)
    {
        int horz=i;
        int vert=h-1;
        int forced=w-i-1;
        int free=w*h-1-forced-2*horz-2*vert;
        int q=(calcu(horz+vert-1,horz)*modpow(s+1,free))%mod;
        q=(q*sum(horz,vert,forced,s))%mod;
        ans=(ans+q)%mod;
    }

    for(int j=0;j<=h-2;j++)
    {
        int horz=w-1;
        int vert=j;
        int forced=h-j-1;
        int free=w*h-1-forced-2*horz-2*vert;
        int q=(calcu(horz+vert-1,vert)*modpow(s+1,free))%mod;
        q=(q*sum(horz,vert,forced,s))%mod;
        ans=(ans+q)%mod;
    }

    printf("%d\n",ans);

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39662197/article/details/80424249