Codeforces1548 C. The Three Little Pigs(组合数学+dp)

题意:

在这里插入图片描述

解法:

对 于 给 定 的 x , a n s = ∑ i = 0 n C 3 i x C ( n , m ) 可 以 预 处 理 逆 元 然 后 O ( 1 ) 算 . 对 于 单 个 x , 累 加 C ( 3 i , x ) 可 以 O ( n ) 计 算 答 案 . 但 是 这 题 是 多 组 数 据 , 需 要 优 化 . 考 虑 不 同 的 x 之 间 是 否 存 在 递 推 关 系 . 即 考 虑 利 用 x = t 的 答 案 推 出 x = t + 1 的 答 案 . − − − − − 已 知 ∑ i = 0 n C 3 i x , 要 推 出 ∑ i = 0 n C 3 i x + 1 令 d [ x ] [ j = 0 / 1 / 2 ] 表 示 ∑ i = 0 n C 3 i + j x 那 么 有 式 子 : 1. d [ x + 1 ] [ 1 ] = d [ x + 1 ] [ 0 ] + d [ x ] [ 0 ] 2. d [ x + 1 ] [ 2 ] = d [ x + 1 ] [ 1 ] + d [ x ] [ 1 ] 3. d [ x + 1 ] [ 0 ] + d [ x + 1 ] [ 1 ] + d [ x + 1 ] [ 2 ] = C 3 n + 3 x + 2 式 子 解 释 : 1 和 2 : d [ x + 1 ] [ 1 ] = ∑ i = 0 n C 3 i + 1 x + 1 = ∑ i = 0 n [ C 3 i x + 1 + C 3 i x ] = ∑ i = 0 n C 3 i x + 1 + ∑ i = 0 n C 3 i x = d [ x + 1 ] [ 0 ] + d [ x ] [ 0 ] d [ x + 1 ] [ 2 ] 同 理 . 3 : d [ x + 1 ] [ 0 ] + d [ x + 1 ] [ 1 ] + d [ x + 1 ] [ 2 ] = ∑ i = 0 n [ C 3 i x + 1 + C 3 i + 1 x + 1 + C 3 i + 2 x + 1 ] = ∑ i = 0 3 n + 2 C i x + 1 = C 3 n + 3 x + 2 那 么 d [ x + 1 ] [ 0 ] = C 3 n + 3 x + 2 − d [ x + 1 ] [ 1 ] − d [ x + 1 ] [ 2 ] 三 个 变 量 三 个 式 子 , 可 以 推 出 转 移 方 程 : 1. d [ x + 1 ] [ 0 ] = ( C 3 ∗ n + 3 x + 2 − 2 d [ x ] [ 0 ] − d [ x ] [ 1 ] ) / 3 2. d [ x + 1 ] [ 1 ] = d [ x + 1 ] [ 0 ] + d [ x ] [ 0 ] 3. d [ x + 1 ] [ 2 ] = d [ x + 1 ] [ 1 ] + d [ x ] [ 1 ] 边 界 : d [ 0 ] [ 0 ] = d [ 0 ] [ 1 ] = d [ 0 ] [ 1 ] = n + 1 答 案 : 对 于 给 定 的 x , d [ x ] [ 0 ] 就 是 答 案 . 对于给定的x,ans=\sum_{i=0}^nC_{3i}^x\\ C(n,m)可以预处理逆元然后O(1)算.\\ 对于单个x,累加C(3i,x)可以O(n)计算答案.\\ 但是这题是多组数据,需要优化.\\ 考虑不同的x之间是否存在递推关系.\\ 即考虑利用x=t的答案推出x=t+1的答案.\\ -----\\ 已知\sum_{i=0}^nC_{3i}^x,要推出\sum_{i=0}^nC_{3i}^{x+1}\\ 令d[x][j=0/1/2]表示\sum_{i=0}^nC_{3i+j}^x\\ 那么有式子:\\ 1.d[x+1][1]=d[x+1][0]+d[x][0]\\ 2.d[x+1][2]=d[x+1][1]+d[x][1]\\ 3.d[x+1][0]+d[x+1][1]+d[x+1][2]=C_{3n+3}^{x+2}\\ 式子解释:\\ 1和2:\\ d[x+1][1]=\sum_{i=0}^nC_{3i+1}^{x+1}\\ =\sum_{i=0}^n[C_{3i}^{x+1}+C_{3i}^{x}]\\ =\sum_{i=0}^nC_{3i}^{x+1}+\sum_{i=0}^nC_{3i}^x\\ =d[x+1][0]+d[x][0]\\ d[x+1][2]同理.\\ 3:\\ d[x+1][0]+d[x+1][1]+d[x+1][2]\\ =\sum_{i=0}^n[C_{3i}^{x+1}+C_{3i+1}^{x+1}+C_{3i+2}^{x+1}]\\ =\sum_{i=0}^{3n+2}C_{i}^{x+1}=C_{3n+3}^{x+2}\\ 那么d[x+1][0]=C_{3n+3}^{x+2}-d[x+1][1]-d[x+1][2]\\ 三个变量三个式子,可以推出转移方程:\\ 1.d[x+1][0]=(C_{3*n+3}^{x+2}-2d[x][0]-d[x][1])/3\\ 2.d[x+1][1]=d[x+1][0]+d[x][0]\\ 3.d[x+1][2]=d[x+1][1]+d[x][1]\\ 边界:\\ d[0][0]=d[0][1]=d[0][1]=n+1\\ 答案:\\ 对于给定的x,d[x][0]就是答案. x,ans=i=0nC3ixC(n,m)O(1).x,C(3i,x)O(n).,.x.x=tx=t+1.i=0nC3ix,i=0nC3ix+1d[x][j=0/1/2]i=0nC3i+jx:1.d[x+1][1]=d[x+1][0]+d[x][0]2.d[x+1][2]=d[x+1][1]+d[x][1]3.d[x+1][0]+d[x+1][1]+d[x+1][2]=C3n+3x+2:12:d[x+1][1]=i=0nC3i+1x+1=i=0n[C3ix+1+C3ix]=i=0nC3ix+1+i=0nC3ix=d[x+1][0]+d[x][0]d[x+1][2].3:d[x+1][0]+d[x+1][1]+d[x+1][2]=i=0n[C3ix+1+C3i+1x+1+C3i+2x+1]=i=03n+2Cix+1=C3n+3x+2d[x+1][0]=C3n+3x+2d[x+1][1]d[x+1][2],:1.d[x+1][0]=(C3n+3x+22d[x][0]d[x][1])/32.d[x+1][1]=d[x+1][0]+d[x][0]3.d[x+1][2]=d[x+1][1]+d[x][1]:d[0][0]=d[0][1]=d[0][1]=n+1:x,d[x][0].

code:
#include<bits/stdc++.h>
// #define MULTI_CASE
// #define SYNC_OFF
#define PI pair<int,int>
// #define int long long
using namespace std;
// const int mod=998244353;
const int mod=1e9+7;
const int maxm=6e6+5;
int n,q;
int d[maxm][3];
int fac[maxm],inv[maxm];
int ppow(int a,int b,int mod){
    int ans=1%mod;a%=mod;
    while(b){if(b&1)ans=1ll*ans*a%mod;a=1ll*a*a%mod;b>>=1;}
    return ans;
}
int C(int n,int m){
    if(m<0||m>n)return 0;
    return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void C_init(){
    fac[0]=1;
    for(int i=1;i<maxm;i++)fac[i]=1ll*fac[i-1]*i%mod;
    inv[maxm-1]=ppow(fac[maxm-1],mod-2,mod);
    for(int i=maxm-2;i>=0;i--)inv[i]=1ll*inv[i+1]*(i+1)%mod;
}
void solve(){
    C_init();
    scanf("%d%d",&n,&q);
    d[0][0]=d[0][1]=d[0][2]=n+1;
    int inv3=ppow(3,mod-2,mod);
    for(int x=0;x<n*3;x++){
        d[x+1][0]=(1ll*C(3*n+3,x+2)-d[x][1]-2*d[x][0])%mod*inv3%mod;
        d[x+1][1]=(d[x+1][0]+d[x][0])%mod;
        d[x+1][2]=(d[x+1][1]+d[x][1])%mod;
    }
    for(int i=1;i<=q;i++){
        int x;scanf("%d",&x);
        int ans=d[x][0];
        ans=(ans%mod+mod)%mod;
        printf("%d\n",ans);
    }
}
void Main(){
    #ifdef MULTI_CASE
    int T;cin>>T;while(T--)
    #endif
    solve();
}
void Init(){
    #ifdef SYNC_OFF
    ios::sync_with_stdio(0);cin.tie(0);
    #endif
    #ifndef ONLINE_JUDGE
    freopen("../in.txt","r",stdin);
    freopen("../out.txt","w",stdout);
    #endif
}
signed main(){
    Init();
    Main();
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值