2018年icpc沈阳赛区C题

简单的计数题,题意是让你对一个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);

            }
        }
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章