2018-2019 ACM-ICPC, Asia Shenyang現場賽C && CodeForces 101955C

題意:

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

 

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