Codeforces587B-DP+优化

来源:互联网 发布:c4d软件 编辑:程序博客网 时间:2024/06/01 08:02

Codeforces587B-Duff in Beach
传送门
题意:
给出一个有l个数的序列,序列每n个数一循环,在每个循环里取一个数,一共取1-k个数,要求取出来的子序列要递增,求方案数。n×k≤1e6 l≤1e18

Solution:
DP,f[i][j]表示取了i次,最后一项取的位置是j的方案数,我们能迅速的想到一个转移方程:

f[i][j]=k=0,akajn1f[i1][k]

发现暴力转移会T,考虑优化:
然后就写了2小时树状数组最后发现我写的方式无法查询TAT
经过机房神犇点拨(orz ckw),发现了每个新状态的转移是不受i的限制的,所以说我们可以把整个数组排序后用前缀和来优化转移。我们可以记录一个sum[i]表示转移到第i层后的答案和,设f[i]表示所选的最后一项的位置是i的方案数,那么f[i]=sum[in1],最后统计答案时,对于每个f[i],它对答案的贡献为((li1n+1)f[i](下标从0开始所以要-1),至于为什么相信大家仔细思考一下就可以知道了。

代码:

#include<cstdio>#include<iostream>#include<algorithm>using namespace std;int n,k;long long l;int mod=1000000007;long long f[1000100];int sum[1000010];pair<int,int> p[1000100];int a[1000100],cnt;int ans=0;void plu(int &a,int b){    a=(1ll*a+b)%mod;}int main(){    scanf("%d%lld%d",&n,&l,&k);    for (int i=0;i<n;i++)        scanf("%d",&a[i]);    for (int i=0;i<n*k;i++)        p[i]=make_pair(a[i%n],i);    sort(p,p+n*k);    for (int i=0;i<n*k;i++)    {        if (p[i].second<n) f[p[i].second]=1;        else f[p[i].second]=sum[p[i].second/n-1];        plu(sum[p[i].second/n],f[p[i].second]);        if (p[i].second<l)        {            plu(ans,(1ll*f[p[i].second]*(((l-p[i].second-1)/n)%mod+1))%mod);        }    }    printf("%d",ans);}

PS:终于会在markdown上写数学公式了QWQ

原创粉丝点击