zoukankan      html  css  js  c++  java
  • 排队(递推)

    【问题描述】

          小sin所在的班有n名同学,正准备排成一列纵队,但他们不想按身高从矮到高排,那样太单调,太没个性。他们希望恰好有k对同学是高的在前,矮的在后,其余都是矮的在前,高的在后。如当n=5,k=3时,假设5人从矮到高分别标为1、2、3、4、5,则(1,5,2,3,4)、(2,3,1,5,4)、(3,1,4,2,5)都是可行的排法。小sin想知道总共有多少种可行排法。

    【输入】

          输入文件名为lineup.in。

          一行两个整数n和k,意义见问题描述。

    【输出】

          输出文件名为lineup.out。

          输出一个整数,表示可行排法数。由于结果可能很大,请输出排法数mod 1799999的值。

    【输入样例1】

    5 3

    【输出样例1】

    15

    【数据范围】

          对于20%的数据,有n≤10,k≤40;

          对于60%的数据,有n≤100,k≤500;

          对于100%的数据,有n≤100,k≤n*(n-1)/2。

    此题是求逆序对。一开始想到暴力算法——直接枚举,结果只过了一组数据。。。

    后来经同学讲解,原来正解是用递推算法,很后悔当时写完枚举后没有用小数据找规律。。。。。。

    用递推,f[i,j]表示{an}前i项之和为j的方案数,f[i,j]=f[i-1,j]+f[i-1,j-1]+…+f[i-1,j-i+1]。时间复杂度O(n2k)。

    优化:将j变成j-1,可以得出f[i,j-1]=f[i-1,j-1]+…+f[i-1,j-i] 两式相减得:

    f[i,j]=f[i-1,j]+f[i,j-1]-f[i-1,j-1]

    这也给了我一个教训,写完暴力算法后要学会用小数据找正解的思路。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    long long f[305][5000];
    long long n,k;
    long long sum=0;
    int main()
    {
      freopen("lineup.in","r",stdin);
      freopen("lineup.out","w",stdout);
      cin>>n>>k;
      for(int i=1;i<=n;i++)
      f[i][0]=1;
      for(int i=1;i<=n;i++)
      {
        sum+=i-1;
        for(int j=1;j<=k;j++)
        {
          if(j>sum)break;
          f[i][j]=(f[i][j-1]+f[i-1][j])%1799999;
          if(i<=j)
          f[i][j]=(f[i][j]-f[i-1][j-i]+1799999)%1799999;
        }
      }
      cout<<f[n][k]%1799999;
      return 0;
    }

  • 相关阅读:
    AngularJs+bootstrap搭载前台框架——准备工作
    Texygen文本生成,交大计算机系14级的朱耀明
    64个命令,每天一个linux命令目录, shutdown,tee,rcp,
    10个常用的ps命令总结,参数
    典型的知识库/链接数据/知识图谱项目
    十个Chatbot框架介绍
    Shell实现多级菜单系统安装维护脚本实例分享
    Java中判断字符串是否为数字的五种方法
    Shell中判断字符串是否为数字的6种方法分享
    shell产生随机数七种方法
  • 原文地址:https://www.cnblogs.com/937337156Zhang/p/5674890.html
Copyright © 2011-2022 走看看