Loading

11.19 模拟赛

补题链接

赛时 100 + 80 + 30 + 0

t2因为双向边没开两倍似了。

A.

小明得到了一个数组 \(p\),这个数组中的元素是一个 1 到 \(n\) 的排列。小明每次可以选择一个满足 \(p_i < p_{i+1} (1 \le i < n)\) 的位置,消除 p_i 或 p_{i+1}。
小明觉得数组的元素实在太多了,他想知道能不能消除到只有一个元素。
可以的话请输出 ,否则输出 。

https://codeforces.com/problemset/problem/1375/C

简单结论,只需要判断 \(a_1 < a_n\) 即可。

代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 7;
int a[N];
void solve() {
    int n;
    cin >> n;
    for(int i = 1; i <= n; i ++) cin >> a[i];
    if(a[1] < a[n]) cout << "YES\n";
    else cout << "NO\n";
}
int main() {
    freopen("C.in", "r", stdin);
    freopen("C.out", "w", stdout);
    int T;
    cin >> T;
    while(T --) solve();
}

B.

将一棵 \(n\) 个点的树通过切割任意条边,使得其划分成若干个大小相同的连通块,求方案数

结论:划分成大小为 \(i\) 的连通块,当且仅当树上有 \(n/i\) 个点的字数大小是 \(i\) 的倍数。

推一推就出来了,不证明了。

代码
#include<bits/stdc++.h>
#define int long long
using namespace std;

const int N = 1e6 + 7;
int head[N], ecnt;
int sz[N], cnt[N];
struct edge {
    int next, to;
}e[N];
void addedge(int u, int v) {
    e[++ ecnt].to = v;
    e[ecnt].next = head[u];
    head[u] = ecnt;
}

void dfs(int u, int fa) {
    sz[u] = 1;
    for(int i = head[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(v == fa) continue;
        dfs(v, u);
        sz[u] += sz[v];
    }
    cnt[sz[u]] ++;
}
vector<int> v;
signed main() {
    freopen("eat.in", "r", stdin);
    freopen("eat.out", "w", stdout);
    memset(head, -1, sizeof head);
    int n;
    cin >> n;
    for(int i = 1; i < n; i ++) {
        int a, b;
        cin >> a >> b;
        addedge(a, b);
        addedge(b, a);
    }
    dfs(1, 0);
    int ans = 0;
    for(int i = 1; i <= n; i ++) {
        if(n % i == 0) v.push_back(i);
    }
    for(int i : v) {
        int now = 0;
        for(int j = i; j <= n; j += i) now += cnt[j];
        if(now * i == n) ans ++;
    }
    cout << ans << endl;
}

C.

\(n\) 种代币,每种面值为 \(a_i\)。每次小明会给每个顾客依次发放任意多次任意一种代币(可以不发)。两个发代币的方案不同当且仅当给两个顾客发放代币的次数不同或发放了不同种的代币,求有多少种发放代币的方案使得发放的总面值小于等于 \(K\)

首先有一个 \(O(nk)\) 的 dp 做法,然后可以优化成 \(O(100k)\),式子是 \(dp_i = \sum_{j=1}^{i-1} cnt_j * dp_{i-j}\)\(cnt_j\) 表示数字 \(j\) 出现个数。

因为最多 100 个数,发现这个可以矩阵快速幂优化。

矩阵在这不写了,因为我不会 latex。。

代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const ll mod = 1e9 + 7;
int n, m, a[maxn];
struct matrix {
    ll a[105][105];
    void I() { for(int i = 1; i <= 101; i++) a[i][i] = 1; }
    matrix() { memset(a, 0, sizeof(a)); }
    matrix operator * (const matrix &x) const {
        matrix res;
        for(int i = 1; i <= 101; i++)
        for(int k = 1; k <= 101; k++) {
            ll t = a[i][k];
            for(int j = 1; j <= 101; j++)
                res.a[i][j] = (res.a[i][j] + t * x.a[k][j]) % mod;
        }
        return res;
    }
} change, ans;
matrix ksm(matrix x, int y) {
    matrix res;
    res.I();
    while(y) {
        if(y & 1) res = res * x;
        x = x * x;
        y >>= 1;
    }
    return res;
}
int main() {
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> m;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) {
        change.a[1][a[i]]++;
        change.a[101][a[i]]++;
    }
    for(int i = 2; i <= 100; i++) change.a[i][i - 1] = 1;
    change.a[101][101] = 1;
    memset(ans.a, 0, sizeof(ans.a));
    ans.a[1][1] = 1; ans.a[101][1] = 1;
    ans = ksm(change, m) * ans;
    cout << ans.a[101][1] << '\n';
    return 0;
}
posted @ 2024-11-20 00:06  你说得太对辣  阅读(6)  评论(0编辑  收藏  举报