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;
    }

  • 相关阅读:
    python-day24(模块语法)
    python-day23(正则表达式,RE)
    python-day22(序列化)
    python-day21(模块初级)
    python-day20(继承)
    python-day19(约束和异常处理)
    python-day18(反射)
    延迟任务
    亚马逊服务器创建root用户
    sqlalchemy orm
  • 原文地址:https://www.cnblogs.com/937337156Zhang/p/5674890.html
Copyright © 2011-2022 走看看