[题解]CF1811G2 Vlad and the Nice Paths (hard version)

因为我是彩笔,所以我不会组合数,只会暴力。

思路

由 Easy Version 得到的状态转移方程:

dpi,j={p=1p<idpp,j1(jmodk=1)p=1p<icp=cidpp,j1(otherwise)

然后你发现对于上面的式子你可以用一个前缀和优化成 Θ(n2) 的,对于第二个式子你考虑也运用类似与前缀和的方式解决。

定义 fi,j 表示,当前取出 j 个颜色为 i 的瓷砖的方案数,于是第二个式子就可以转化成 fci,j1。然后对于每一个 i,都可以将 fci,j 更新为 fci,j+dpi,j

毒瘤警告:有毒瘤 Hack 使得答案的总和模 109+7 等于 0,所以你还需要额外的标记数组判断这个位置是为是真的有值。

Code

#include <bits/stdc++.h>  
#define re register  
#define Add(a,b) (((a) + (b)) % mod)  
  
using namespace std;  
  
const int N = 5010,mod = 1e9 + 7;  
int n,k;  
int arr[N],dp[N][N],s[N][N],f[N][N];  
bool sdp[N][N],ss[N][N],sf[N][N];  
  
inline int read(){  
    int r = 0,w = 1;  
    char c = getchar();  
    while (c < '0' || c > '9'){  
        if (c == '-') w = -1;  
        c = getchar();  
    }  
    while (c >= '0' && c <= '9'){  
        r = (r << 3) + (r << 1) + (c ^ 48);  
        c = getchar();  
    }  
    return r * w;  
}  
  
inline void solve(){  
    dp[0][0] = s[0][0] = 1;  
    sdp[0][0] = ss[0][0] = true;  
    n = read();  
    k = read();  
    for (re int i = 1;i <= n;i++) arr[i] = read();  
    for (re int i = 1;i <= n;i++){  
        for (re int j = 0;j <= n;j++){  
            dp[i][j] = s[i][j] = f[i][j] = 0;  
            sdp[i][j] = ss[i][j] = sf[i][j] = false;  
        }  
    }  
    for (re int i = 1;i <= n;i++){  
        for (re int j = i;~j;j--){  
            if (j % k == 1){  
                dp[i][j] = Add(dp[i][j],s[i - 1][j - 1]);  
                sdp[i][j] |= ss[i - 1][j - 1];  
            }  
            else if (j){  
                dp[i][j] = Add(dp[i][j],f[arr[i]][j - 1]);  
                sdp[i][j] |= sf[arr[i]][j - 1];  
            }  
            s[i][j] = Add(s[i - 1][j],dp[i][j]);  
            ss[i][j] |= ss[i - 1][j] | sdp[i][j];  
            f[arr[i]][j] = Add(f[arr[i]][j],dp[i][j]);  
            sf[arr[i]][j] |= sdp[i][j];  
        }  
    }  
    for (re int j = n;~j;j--){  
        if (j % k == 0){  
            int ans = 0;  
            bool falg = false;  
            for (re int i = 1;i <= n;i++){  
                ans = Add(ans,dp[i][j]);  
                falg |= sdp[i][j];  
            }  
            if (falg){  
                printf("%d\n",ans);  
                return;  
            }  
        }  
    }  
    puts("1");  
}  
  
int main(){  
    int T;  
    T = read();  
    while (T--) solve();  
    return 0;  
}  

作者:WaterSun

出处:https://www.cnblogs.com/WaterSun/p/18266713

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   WBIKPS  阅读(5)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
点击右上角即可分享
微信分享提示