zoukankan      html  css  js  c++  java
  • 组合数 (选定思想) dp cf1000D

    http://codeforces.com/problemset/problem/1000/D

    参考自:https://www.cnblogs.com/hua-dong/p/9238795.html

    题意:给定序列,问有多少子序列(不一定连续),满足可以划分为若干个组,给个组的第一个等于区间长度-1;

    思路:关键就在于区间的开头,由此我们从后往前考虑,dp[ i ] 表示以 i 开头,满足题意的数量,sum[ i ] 表示 i 及以后所有的可能情况。

    对于 i ,可选的区间为 [ i , j ] , j 的范围是 i+a[ i ] ~ n,再利用选定的思想,这一段区间的可能情况就有 C (  a[ i ] -1 , j - i -1 ) ,接着,再乘上(1+sum[ j +1 ]),

    这就是对乘法思想的利用,而这个 1 代表只选前面一个段的情况,通过不断的累加就得到 dp[ i ],再累加就得到 sum[ i ]。

    #include<bits/stdc++.h>
    #define ll long long 
    using namespace std;
    const int Mod=998244353;
    const int maxn=1010;
    int a[maxn],dp[maxn],sum[maxn];
    int c[maxn][maxn],ans;
    int main()
    {
        int N,i,j;
        scanf("%d",&N);
        for(i=0;i<=N;i++) c[i][0]=1,c[i][1]=i,c[i][i]=1;
        for(i=1;i<=N;i++)
         for(j=1;j<=N;j++)
           c[i][j]=(c[i-1][j]+c[i-1][j-1])%Mod;
        for(i=1;i<=N;i++) scanf("%d",&a[i]); 
        for(i=N;i>=1;i--){
            if(a[i]>0&&i+a[i]<=N){
                for(j=i+a[i];j<=N;j++){
                    (dp[i]+=(ll)c[j-i-1][a[i]-1]*(1+sum[j+1])%Mod)%=Mod;  //这里的1是指只有一个段的情况
                    printf("%d %d 
    ", c[j-i-1][a[i]-1],(1+sum[j+1]));
                }
            }
            sum[i]=(sum[i+1]+dp[i])%Mod;
            // printf("%d
    ", sum[i]);
        }
        printf("%d
    ",sum[4]);
        return 0;
    }
    
    
    
    
    
    
    
    
    
    // #include <iostream>
    // #include <cstdio>
    // #include <cstdlib>
    // #include <cstring>
    // #include <cmath>
    // #define qwq(i,j,k)      for(int i=j; i<k; ++i)
    // #define qeq(i,j,k)      for(int i=j; i<=k; ++i)
    // #define mem(a,b)        memset(a, b, sizeof(a))
    // using namespace std;
    // typedef long long ll;
    // const int mx = 1e5+5;
    // const int maxn = 3e3+5;
    // const int inf= 0x3f3f3f3f;
    // // const ll mod = 1e9+7;
    // const ll INF = 1e18+100;
    // int n, m;
    // int cas, tol, T;
    
    // ll C[maxn][maxn];
    // ll fac[mx]; //i!
    // ll inv[mx]; //i!在取模mod的情况下的逆元
    
    // // ll fpow(ll a, ll b) {
    // //     ll ans = 1;
    // //     while(b) {
    // //         if(b & 1)
    // //             ans = ans * a % mod;
    // //         a = a * a % mod;
    // //         b >>= 1;
    // //     }
    // //     return ans;
    // // }
    
    // const ll mod=998244353;
    // void handle() {
    // //    fac[0] = 1;
    // //    for(int i=1; i<=mx; ++i) {
    // //        fac[i] = fac[i-1]*i%mod;    //阶乘的表
    // //    }
    // //    inv[mx] = fpow(fac[mx], mod-2);
    // //    for(int i=mx-1; i>=1; --i) {
    // //        inv[i] = inv[i+1] * (i+1) % mod;
    // //    }
    //     C[0][0] = 1;
    //     C[1][0] = C[1][1] = 1;
    //     for(int i=2; i<maxn; ++i) {
    //         for(int j=0; j<=i; ++j) {
    //             C[i][j] = j==0 ? 1 : (C[i-1][j]%mod+C[i-1][j-1]%mod)%mod;
    //         }
    //     }
    // }
    
    // ll a[maxn];
    // ll b[maxn];
    // ll ans;
    
    // int main() {
    //     //打表O(N^2)   n 1e3左右
    //     handle();
    //     // for(int i=1; i<=10; ++i) {
    //     //     for(int j=0; j<=i; ++j) {
    //     //         printf("C[%d][%d] = %lld
    ", i, j, C[i][j]);
    //     //     }
    //     // }
    //     ans=0;
    //     scanf("%d",&n);
    //     for(int i=1; i<=n; i++){
    //         cin>>a[i];
    //     }
    //     for(int i=1; i<=n; i++){
    //         if(a[i]>0 && a[i]+i<=n){
    //             b[i] = C[n-i][ a[i] ];
    //         }
    //     }
    //     for(int i=n-1; i>=1; i--){
    //         if(b[i]!=0){
    //             ll sum=0;
    //             for(int j=n-1; j>=i+a[i]+1; j--){
    //                 // if(a[j]>0 && a[j]+j<=n){
    //                     b[i] += b[j];
    
    //                 // }
    //               // if(i==4) printf("b[4]=%lld
    ", b[i]);
    //             }
    //             // b[i] = (b[i]%mod + b[ i+a[i]+1 ]%mod)%mod;
    //             ans = (ans+b[i])%mod;
    //         }   
    //     }
    //     printf("%d
    ", b[2]);
    //     cout<<ans<<endl;
    
    //     return 0;
    // }
  • 相关阅读:
    [leetcode]_Search Insert Position
    [leetcode]_Merge Two Sorted Lists
    [leetcode]_Valid Parentheses
    喧闹中坚守底线-徘徊的行走在不知道路在何方的大地上。
    [leetcode]_Longest Common Prefix
    [leetcode]_Remove Nth Node From End of List
    [leetcode]_Roman to Integer
    [leetcode]_Palindrome Number
    策略模式(Strategy)
    面向对象
  • 原文地址:https://www.cnblogs.com/-Zzz-/p/11427423.html
Copyright © 2011-2022 走看看