首页 > 其他 > 详细

jzoj6300. Count

时间:2019-08-14 10:44:31      阅读:56      评论:0      收藏:0      [点我收藏+]
Time Limits: 1000 ms Memory Limits: 524288 KB

Description

技术分享图片

Input

技术分享图片

Output

技术分享图片

Sample Input

5 3 3

Sample Output

3

Data Constraint

技术分享图片

赛时

比赛时一开始只想到30分。
后来突然发现那个k似乎很小。
那么就考虑把每个a都分解成m*p+q的形式。
后者利用DP,前者利用组合数来求一求即可。
然而似乎我打错了,而且时间复杂度估计错误,只拿了30分。(本来能多20分的啊)

题解

上面50分的做法一目了然。
细细来讲就是:
\(A=\sum q\)
那么当\(A\%m==n\%m\)时,就代表可以对答案造成贡献。
由于每个a都是由若干个m相加最后加上个q形成。
由于q的答案利用DP已经求出来了,接下来考虑如何分配这若干个m。
当然组合数(挡板问题)
由于\(\frac n m\)巨大无比,但是k却奇小无比。
怎么办?考虑直接把那个组合数计算的柿子上下约分即可。

接下来考虑优化。
我们看到DP似乎有点没用,那么考虑再利用组合数来代替DP。
我们发现,这个不能直接套组合数,由于有些a可能分配到了比m-1大的数,所以我们要把这部分的答案容斥一下。
注意小细节即可。

标程

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const long long mo=998244353;

long long n,m,ny2,ans,my,ii,kk,x;
long long t,y,a,b,k,gs;
long long zs[10000];
bool bz[10000];
long long jc[10000001];

__attribute__((optimize("-O3")))
long long qsm(long long a,long long b)
{
    long long t=1;
    long long y=a;
    while (b>0)
    {
        if (b%2==1) t=t*y%mo;
        y=y*y%mo;
        b=b/2;
    }
    return t;
}
__attribute__((optimize("-O3")))
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    scanf("%lld%lld%d",&n,&m,&k);
    jc[0]=1;
    for (int i=1;i<=10000000;i++)
    {
        jc[i]=jc[i-1]*i%mo;
    }
    ny2=qsm(2,mo-2);
    for (long long i=1;i<=(m-1)*k;i++)
    {
        if (i%m==n%m)
        {
            long long j=(n/m-i/m);
            my=(jc[i-1]*qsm(jc[k-1]*jc[i-k]%mo,mo-2)%mo);
            x=-1;
            for (long long now=1;now<=k-1;now++)
            {
                ii=i-now*(m-1);
                if (ii<=0) break;
                kk=(jc[k]*qsm(jc[now]*jc[k-now]%mo,mo-2)%mo)*(jc[ii-1]*qsm(jc[k-1]*jc[ii-k]%mo,mo-2)%mo)%mo;
                my=(my+x*kk+mo)%mo;
                x=x*(-1);
            }
            if (j==0)
            {
                ans+=my;
                continue;
            }
            long long op=1;
            for (long long l=1;l<=k-1;l++)
            {
                op=(op*(l%mo))%mo;
            }
            long long oq=1;
            for (long long l=j+1;l<=j+k-1;l++)
            {
                oq=(oq*(l%mo))%mo;
            }
            op=qsm(op,mo-2);
            op=op*oq%mo;
            if (k==1)
            {
                op=1;
            }
            ans=(ans+(op*my)%mo)%mo;
        }
    }
    printf("%lld\n",ans);
}

jzoj6300. Count

原文:https://www.cnblogs.com/RainbowCrown/p/11350378.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!