洛谷P2401 不等数列

题目描述
将1到n任意排列,然后在排列的每两个数之间根据他们的大小关系插入“>”和“<”。问在所有排列中,有多少个排列恰好有k个“<”。答案对2015取模。
注:1~n的排列指的是1~nn个数各出现且仅出现一次的数列。

输入格式
第一行2个整数n,k

输出格式
一个整数表示答案。

输入样例
5 2

输出样例
66

说明
对于30%的数据:n<=10
对于100%的数据:k<n<=1000

思路
fi,j表示前i个数中有j个小于号的方案总数。设有一个数列是这样的:

a<b<c>d<e>f
这个是f6,3的一种方案,如何转移到f7,x就是问题的关键了。
转移到f7,x,就意味着要向这6个数中插一个7,观察它是否会增加(或减少)小于号的数量。如果向这个位置插入7:
a<b
由于7比原数列任何数都大,那么改变后的数列就是这样:
a<7>b
不会增加也不会减少小于号的数量。
那么fi,j就可以从fi1,j转移过来。
那么接下来的问题就是:有几种方法可以让fi,jfi1,j转移?
显然,插入每个小于号都可以这样转移,再加上数列开头的部分,一共j+1个。
接下来讨论另一种情况,向这个位置插入7:
c>d
就变成了:
c<7>d
会增加一个小于号的数量。
那么fi,j也可以从fi1,j1转移。
同理,插入每个大于号都可以这样转移,大于号的数量是(i1)j个,再加上数列结尾的1个,总共ij个。
综上所述,状态转移方程是这样的:
fi,j=fi1,j(j+1)+fi1,j1(ij)

代码

#include <cstdio>

const int maxn=1000;
const int mo=2015;

int f[maxn+10][maxn+10],n,k;

int main()
{
    scanf("%d%d",&n,&k);
    f[0][0]=1;
    for(int i=1; i<=n; i++)
    {
        f[i][0]=1;
        for(int j=1; j<=k; j++)
        {
            f[i][j]=f[i-1][j-1]*(i-j)+f[i-1][j]*(j+1);
            f[i][j]%=mo;
        }
    }
    printf("%d\n",f[n][k]);
    return 0;
}
### 关于洛谷 B3987 朋友数列问题 针对洛谷平台上的编号为B3987的朋友数列题目,该题目的核心在于理解两个数字成为“朋友”的定义以及如何高效计算满足条件的数对数量。 #### 定义与目标 在这个问题中,“朋友”关系被定义为如果一对正整数\(A\)和\(B\)之间存在某种特定的关系,则认为它们互为朋友。具体来说,当且仅当\(A \% 10 = \lfloor B / 10 \rfloor\) 或者 \(B \% 10 = \lfloor A / 10 \rfloor\) 成立时,\(A\) 和 \(B\) 是朋友。这里\(\%\),表示取模运算;而\(\lfloor x \rfloor\)代表不大于\(x\)的最大整数(向下取整)。任务是在给定范围内找出所有的朋友数对并返回其总数[^1]。 #### 解决方案概述 为了有效地解决这个问题,可以采用计数排序的思想来优化查询过程: - **预处理阶段**:创建一个数组用于记录各个可能作为十位或个位数值出现次数; - **遍历区间内的每一个数**:对于当前考察中的每个数,依据上述规则快速定位潜在的朋友候选对象,并通过预先构建好的辅助结构加速匹配操作; - **统计符合条件的结果数目**:每当发现一组新的朋友组合就增加计数器直至完成整个范围扫描为止。 下面给出一段Python代码示例实现了这一思路: ```python def count_friend_pairs(L, R): cnt = [0]*10 # 统计L到R之间的每一位数字出现频率 for num in range(L, R + 1): last_digit = num % 10 first_digit = (num // 10) % 10 if num >= 10 else 0 cnt[last_digit] += 1 if first_digit != last_digit: cnt[first_digit] += 1 result = sum((v * (v - 1)) >> 1 for v in cnt) return result if __name__ == "__main__": L, R = map(int, input().split()) print(count_friend_pairs(L, R)) ``` 这段程序首先初始化了一个大小为10的列表`cnt`用来存储从0至9这十个不同数码在整个闭合区间\[L,R\]内各自出现了几次。接着,在循环体内更新这些统计数据的同时也考虑到了那些只有一位有效数字的情况。最后一步则是利用组合数学原理——即任意选取两件物品的方法数等于C(n,2)=n*(n−1)/2—来进行最终答案的汇总工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值