简单的计数题,题意是让你对一个1到n的一个排列执行k次插入排序,排完序以后要满足最长上升递增子序列的长度至少为n-1,问这样的排列由多少种。做的时候是这样做的,首先考虑前k个正好是前k个,然后后面的最长上升子序列大于等于n-k-1的排列的个数有多少,刚开始手推,发现推出来的公式是错误的,然后这个就打了一下表,之后考虑前面的k个有一个不属于1到k的范围以内,在纸上画了一下,发现第k个值比较特殊,多了n-k-1种,其他的都是一样就把第k+1个值插入放到前面,然后前面这个数插入到后面的空位中就行了。
代码:
#include<bits/stdc++.h>
using namespace std;
int data[1000] = {1, 1, 2, 5, 10, 17, 26, 37, 50, 65, 82, 101, 122, 145, 170,
197, 226, 257, 290, 325, 362, 401, 442, 485, 530, 577, 626, 677, 730, 785, 842,
901, 962, 1025, 1090, 1157, 1226, 1297, 1370, 1445, 1522, 1601,
1682, 1765, 1850, 1937, 2026, 2117, 2210, 2305, 2402, 2501,
};
using ll=long long ;
int main()
{
int t;
while(scanf("%d",&t)!=EOF)
{
int x=1;
ll n,k,q;
while(t--)
{
scanf("%lld%lld%lld",&n,&k,&q);
k=min(n,k);
if(k==1)
{
printf("Case #%d: %I64d\n",x++,data[n]%q);
}
else if(k==n)
{
ll ans=1;
for(ll i=1; i<=n; i++)
ans=ans*i%q;
printf("Case #%d: %I64d\n",x++,ans);
}
else
{
ll ans=1;
for(int i=1; i<=k; i++)
{
ans=ans*i%q;
}
ans = ans*(data[n-k] + k*(n-k)+n-k-1)%q;
printf("Case #%d: %I64d\n",x++,ans);
}
}
}
}
本文探讨了一道复杂的计数题,旨在寻找满足特定条件的排列数量,这些条件涉及插入排序后的最长上升子序列。文章详细介绍了问题的解决思路,从初始尝试到发现错误的公式,最终通过表格和图形辅助理解,提出了有效的解决方案。代码部分展示了使用C++实现的算法,包括对不同情况的处理,如k等于1、k等于n和k介于1和n之间的特殊情况。
395

被折叠的 条评论
为什么被折叠?



