[2017纪中11-4][ARC071]F-neutral DP

题面
首先考虑假如填了连续的两个数a,b均>=2,那么后面的数一定全是b。先暂时不考虑这种情况。
考虑假如填了一个>=2的数a,那么后面a个数都必须填1,之后才能自由填,于是设计状态f[i]表示从i开始可以自由填的方案数。那么假设上一个自由填>=2的数是d,那么f[i]+=f[i-d-1],假如上一个自由填的是1,f[i]+=f[i-1],总之不能转移i-2就是了。
但考虑到有一些>=2的a使得要到n之后的某个位置才能自由填,所以上述第一种转移要转移到2*n,第二种转移到n即可(后面的重复了)。
在考虑连续两个>=2的情况,考虑这两个填的位置,只需要把f[1]~f[n-2]乘上(n-1)*(n-1)加到答案中即可。
代码:

#include<iostream>
#include<cstdio>
#define ll long long
#define up(a,b) a=(a+b)%mod
using namespace std;
const int mod=1000000007;
const int maxn=2000100;
int n;
ll f[maxn],s[maxn],ans=0;
int main()
{
    scanf("%d",&n);
    f[0]=s[0]=1;
    for(int i=1;i<=2*n;i++)
    {
        int l=max(0,i-n-1),r=min(n-1,i-3);
        if(l<=r) f[i]=(s[r]-(l==0?0:s[l-1])+mod)%mod;
        if(i<=n) up(f[i],f[i-1]);
        s[i]=(s[i-1]+f[i])%mod;
    }
    for(int i=n;i<=2*n;i++)
        up(ans,f[i]);
    for(int i=0;i<=n-2;i++)
        up(ans,f[i]*(n-1)%mod*(n-1)%mod);
    printf("%lld",ans);     
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值