2018-2019 ACM-ICPC, Asia Shenyang现场赛C && CodeForces 101955C

推公式 同时被 2 个专栏收录
1 篇文章 0 订阅
1 篇文章 0 订阅

题意:

n[1,50],k[1,50],p[1e8,1e9].

求有多少 1 到 n 的排列满足:将前 k 个的数排列以后,最长上升子序列长度为 n−1 以上。

瞎搞:

用next_permutation打表,然后肉眼找出规律。

打表代码。

#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
//#define pa pair<int, int>
// const int maxn = 1e6+5;

int a[100], b[100];
int lis(int b[], int n) {
    int *d = new int[n];
    int len = 1;
    for (int i = 0; i < n; i++) {
        d[i] = 1;
        for (int j = 0; j < i; j++) {
            if (b[j] <= b[i] && d[j] + 1 >= d[i]) {
                d[i] = d[j] + 1;
            }
        }
        len = max(len, d[i]);
    }
    delete[] d;
    return len;
}
int db(int n, int m) {
    vector<int> v;
    for (int i = 0; i < n; i++) {
        a[i] = i + 1;
    }
    int cnt = 0;
    do {
        for (int i = 0; i < n; i++) b[i] = a[i];
        sort(b, b + m);
        int len = lis(b, n);
        if (len + 1 >= n) cnt++;
    } while (next_permutation(a, a + n));
    return cnt;
}
int main() {
    for (int n = 1; n < 10; n++) {
        for (int m = 1; m <= n; m++) {
            cout << n << ' ' << m << "   " << db(n, m) << endl;
        }
        cout << endl;
    }
    int a;
    cin >> a;
}

公式乱搞:

#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
ll mod;
ll jiecheng[60];
void db() {
    jiecheng[0] = jiecheng[1] = 1;
    for (int i = 2; i < 55; i++) {
        jiecheng[i] = jiecheng[i - 1] * i % mod;
    }
}
int main() {
    int T, cas = 0;
    cin >> T;
    while (T--) {
        int n, k;
        cin >> n >> k >> mod;
        k = min(n, k);
        db();
        cout << "Case #" << ++cas << ": ";
        ll ans = jiecheng[k];
        ll add = (jiecheng[k + 1] - jiecheng[k] + mod) % mod;
        ll add2 = jiecheng[k] * 2 % mod;
        for (int i = k + 1; i <= n; i++) {
            ans = (ans + add) % mod;
            add = (add + add2) % mod;
        }
        cout << ans << endl;
    }
}

正解:

题解:前k个排序之后分四种情况讨论:

1. 排序之后整个就有序了:k!

2. 排序之后前面是 1 到 k,后面最长上升子序列的长度是 n−k−1:k!⋅(n−k−1)^2。

3. 排序之后前 k 个数里有一个被换成了 k+1,被换的那个数可以插到后面里面去:k!⋅k(n−k)。

4. 排序之后前 k 个数里有一个(只能是 k)被换成了 k+2 以上的数,后面 n−k 个数必须有序:k!⋅(n−k−1)。

综上,答案就是 k!(1+(n−k−1)2+k(n−k)+(n−k−1))。

FROM:https://acm.ecnu.edu.cn/wiki/index.php?title=2018_ACM-ICPC_Shenyang_Regional_Onsite

代码:

#include <bits/stdc++.h>
#define mem(sx, sy) memset(sx, sy, sizeof(sx))
typedef long long ll;
typedef unsigned long long ull;
const double eps = 1e-8;
const double PI = acos(-1.0);
const ll llINF = 0x3f3f3f3f3f3f3f3f;
const int INF = 0x3f3f3f3f;
using namespace std;
//#define pa pair<int, int>
const int maxn = 1e5 + 5;
ll mod;
ll jiecheng[60];
next_permutation
void db() {
    jiecheng[0] = jiecheng[1] = 1;
    for (int i = 2; i < 55; i++) {
        jiecheng[i] = jiecheng[i - 1] * i % mod;
    }
}
int main() {
    int T, cas = 0;
    cin >> T;
    while (T--) {
        int n, k;
        cin >> n >> k >> mod;
        k = min(n, k);
        db();
        cout << "Case #" << ++cas << ": ";
        ll ans = jiecheng[k] *
                 (1 + (n - k - 1) * (n - k - 1) + k * (n - k) + (n - k - 1)) % mod;
        cout << ans << endl;
    }
}

 

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值