zoukankan      html  css  js  c++  java
  • 一. 至少转最多

    处理何种问题:有m 种类型的物品(每种类型的物品个数可视为无限),从中选出n个物品,求物品s至少有一次连续选k件的方案数。

    例题:抛硬币,抛n次,求正面至少连续出现k次的种数。抛3次,连续出现2次正面的种数是3(110,011,111)。

    性能:时间复杂度为O(nm),空间复杂度也是(nm)。

    原理:设事件A={最多选n个s物品连续},B={最多选k-1个s物品连续},

    A-  B={至少选k件s件物品连续}。 dp[i][j] 表示第i次选择时选择j 物品时满足

    条件的方案数,注意:dp[i][j]求的是最多选s个物品连续的情况;

    l  对于非s物品,对整个没有影响,所以dp[i][~s]=sum[i-1];

    l  对于s物品:

    n  当i<=u 时(n,k-1都为u),dp[i][s]=sum[i-1](因为肯定没超过n)。

    n  当i==u+1时,dp[i][s]=sum[i-1]-1(这种情况下,只有一种可能会超过n)。

    n  当i>u+1时,dp[i][s]=sum[i-1]-dp[i-u-1][~s](此时要减去i前面已经出现连续u个s的情况,即从i-u到i-1这一段都是s的情况,其个数就是

    dp[i-u-1][~s]之和,为什么没有减掉dp[i-u-1][s],因为当i-u-1为s时,所有i-1都肯定是~s了)唉,dp就是在人脑里跑递归啊。

    实现步骤:至少转最多,用DP实现。

    备注:此题涉及面比较广,可作为入门dp的练习题,且拓展性也不错,曾遇到一个至少+一个最多。写此题目的不是为了做模板用,只为加深dp理解。

    输入样例解释

    10 3 2 5 //n m s k

    输出样

    1053 //方案数

    #include<iostream>
    #include<cstdio>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    int n,m,s,k,ans;
    const int mod=1e9+7;
    long long sum[1000010];
    long long dp[1000010][10];
    
    long long f(int u)
    {
        for(int i=1; i<=n; ++i)
        {
            for(int j=0;j<m;++j)
            {
                if(j!=s)
                    dp[i][j]=sum[i-1];
            }
            if(i<=u)
                dp[i][s]=sum[i-1];
            else if(i==u+1)
                dp[i][s]=sum[i-1]-1;
            else if(i>u+1)
            {
                dp[i][s]=sum[i-1];
                for(int j=0;j<m;++j)
                {
                    if(j!=s)
                        dp[i][s]-=dp[i-u-1][j];
                }
    
            }
    
            sum[i]=0;
            for(int j=0;j<m;++j)
            {
                sum[i]+=dp[i][j];
            }
        }
        return sum[n];
    }
    
    int main()
    {
        while(~scanf("%d%d%d%d",&n,&m,&s,&k))
        {
            sum[0]=1;
            printf("%lld
    ",f(n)-f(k-1));
        }
        return 0;
    }
    
    /*
    //暴力验证代码
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int n,m,s,k,ans;
    int arr[100];
    
    void dfs(int ctor)
    {
        if(ctor>n)
        {
            int sum=0,flag=0;
            for(int i=1;i<=n;++i)
            {
                if(arr[i]==s)
                {
                    if(arr[i]!=arr[i-1])
                        sum=1;
                    else if(arr[i]==arr[i-1])
                        ++sum;
                }
                else
                    sum=0;
                if(sum>=k)
                    flag=1;
            }
            if(flag)
            {
    
                ++ans;
                printf("%d:",ans);
                for(int i=1;i<=n;++i)
                    printf("%d",arr[i]);
                printf("
    ");
            }
    
        }
        else
        {
            for(int i=0;i<m;++i)
            {
                arr[ctor]=i;
                dfs(ctor+1);
            }
        }
    }
    
    
    int main()
    {
        while(~scanf("%d%d%d%d",&n,&m,&s,&k))
        {
            ans=0;
            arr[0]=-1;
            dfs(1);
            cout<<ans<<endl;
        }
        return 0;
    }
    */
    

      

  • 相关阅读:
    html5数字和颜色输入框
    WinForm设置右键菜单
    设置窗体透明C#代码
    C#调用windows api示例
    使用VS GDB扩充套件在VS上远端侦错Linux上的C/C++程序
    javascript系统时间测试题
    博客园学习的好地方
    基于jQuery的自适应图片左右切换
    HTML+CSS代码橙色导航菜单
    ASP.NET使用UpdatePanel实现AJAX
  • 原文地址:https://www.cnblogs.com/l1l1/p/9475743.html
Copyright © 2011-2022 走看看