2024.7.13 暑期训练记录(5)

CF

1359E - Modular Stability(组合数学 *2000)

  • 这题应该是能出的,玩样例的时候脑子抽了玩错了(
  • 稍微看几组例子就能发现,最终的答案是由最小的数 a 1 a_1 a1 决定的,之后的数都要是 a 1 a_1 a1 的倍数才行
  • 所以枚举每一个 a 1 a_1 a1 ,答案加上 C n i − 1 k − 1 C_{\frac{n}{i}-1}^{k-1} Cin1k1
#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

int Jc[maxn];

void calJc()	//求 maxn 以内的数的阶乘 不知道开多少就1e6吧爆不了
{
    Jc[0] = Jc[1] = 1;
    for(int i = 2; i < maxn; i++) Jc[i] = Jc[i - 1] * i % mod;
}

int pow(int a, int n, int p) // 快速幂取模
{
    int ans = 1;
    while (n)
    {
        if (n & 1) ans = ans * a % p;
        a = a * a % p;
        n >>= 1;
    }
    return ans;
}

int niYuan(int a, int b)	//费马小定理求逆元
{
    return pow(a, b - 2, b);
}

int C(int a, int b) // 组合数
{
    if(a < b) return 0;
    return Jc[a] * niYuan(Jc[b], mod) % mod * niYuan(Jc[a - b], mod) % mod;
}

void solve()
{
    calJc();
    int n, k;
    cin >> n >> k;
    if (n < k) cout << 0 << '\n';
    else
    {
        int ans = 0;
        for (int i = 1; i <= n - k + 1; i ++ ) // 枚举最小的数
        {
            ans = (ans + C(n / i - 1, k - 1)) % mod;
        }
        cout << ans << '\n';
    }
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t--)
	{
		solve();
	}
}

1399E1 - Weights Division (easy version) (dfs+堆 *2000)

  • 对于一条边的贡献,很容易知道是边权乘使用次数,使用次数就是这条边下面的叶子结点的个数,这个我们用dfs就可以处理出来了
  • 然后用堆,但是这里有一个易错点!堆里的排序规则应该是, ( w − w 2 ) × c n t (w-\frac{w}{2})\times cnt (w2w)×cnt 大的放前面,这个才是操作一次消除的总值,不能把 w × c n t w\times cnt w×cnt 放前面,因为除法下取整会出问题
#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

struct node {
    int w, cnt;
    bool operator< (const node &tmp) const {
        return (w - w / 2) * cnt < (tmp.w - tmp.w / 2) * tmp.cnt;
    }
};

void solve()
{
    int n, S;
    cin >> n >> S;
    vector<vector<PII>> g(n + 1);
    for (int i = 0; i < n - 1; i ++ )
    {
        int u, v, w;
        cin >> u >> v >> w;
        g[u].push_back({v, w});
        g[v].push_back({u, w});
    }
    vector<PII> dp(n + 1); // 当前点的父边要用多少次
    function<void(int, int)> dfs = [&](int u, int fa)
    {
        if (g[u].size() == 1 && u != 1)
        {
            dp[u].first ++ ;
            return;
        }
        for (int i = 0; i < g[u].size(); i ++ )
        {
            int ver = g[u][i].first, w = g[u][i].second;
            if (ver == fa) continue;
            dp[ver].second = w;
            dfs(ver, u);
            dp[u].first += dp[ver].first;
        }
    };
    dfs(1, -1);
    priority_queue<node> q;
    int tot = 0, ans = 0;
    for (int i = 2; i <= n; i ++ )
    {
        tot += dp[i].first * dp[i].second;
        q.push({dp[i].second, dp[i].first});
    }
    while (tot > S)
    {
        auto t = q.top();
        q.pop();
        tot = tot - t.w * t.cnt + t.w / 2 * t.cnt;
        q.push({t.w / 2, t.cnt});
        ans ++ ;
    }
    cout << ans << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	cin >> t;
	while (t--)
	{
		solve();
	}
}

1294F - Three Paths on a Tree(树的直径 *2000)

  • 这一题的思路也基本正确,即直径的两个端点一定选,其余点中选一个最优的
  • 但是实现上出了大问题,自己实现的时候很麻烦,还去找两个端点的lca防止重复计算,实际上重复计算也没什么,最后的结果直接除以2就好了
#include <bits/stdc++.h>

using namespace std;

#define int long long
using i64 = long long;

typedef pair<int, int> PII;
typedef pair<int, char> PIC;
typedef pair<double, double> PDD;
typedef pair<int, PII> PIII;
typedef pair<int, pair<int, bool>> PIIB;

const int N = 1e6 + 10;
const int maxn = 1e6 + 10;
const int mod = 998244353;
const int mod1 = 954169327;
const int mod2 = 906097321;
const int INF = 0x3f3f3f3f3f3f3f3f;

void solve()
{
    int n;
    cin >> n;
    vector<vector<int>> g(n + 1);
    for (int i = 1; i <= n - 1; i ++ )
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    int c = 1, d, e;
    vector<int> dis_c(n + 1), dis_d(n + 1);
    function<void(int, int, vector<int>&)> dfs = [&](int u, int fa, vector<int>&dis)
    {
        for (int v : g[u])
        {
            if (v == fa) continue;
            dis[v] = dis[u] + 1; // 如边有权值,把1换成权值即可
            if (dis[v] > dis[c]) c = v; // 更新最大距离的点
            dfs(v, u, dis);
        }
    };
    dfs(1, -1, dis_d);
    d = c;
    dis_d[c] = 0;
    dfs(c, -1, dis_d);
    dis_c[c] = 0;
    d = c;
    dfs(c, -1, dis_c);
    int ans = 0;
    for (int i = 1; i <= n; i ++ )
    {
        if (i == c || i == d) continue;
        if (dis_c[i] + dis_d[i] + dis_c[c] > ans)
        {
            e = i;
            ans = dis_c[i] + dis_d[i] + dis_c[c];
        }
    }
    cout << ans / 2 << '\n';
    cout << c << ' ' << d << ' ' << e << '\n';
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int t = 1;
	// cin >> t;
	while (t--)
	{
		solve();
	}
}

算法

最大流判定的例题

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Texcavator

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值