TC SRM567 DIV2 T3 MountainsEasy

本文介绍了一种解决特定山峰坐标序列计数问题的方法,包括寻找确定的山峰位置、将问题转化为物品放置问题,并使用容斥原理进行计算。

前言

TC百题计划,走起!

题目描述

今有一图青山绿水,山神安山NN座。重峦叠嶂,峰峰起伏如此:

For 0 <= i < N:
    For 0 <= x < W:
        For 0 <= y <= Y[i] - |x - X[i]|:
            pix[x, y] := 'X'

即是:

..X...
.XXXX.
XXXXXX

如是,山峰坐标多变莫测。今予你山水画一幅,请求山峰坐标的不同序列,答案对109+9取模。

Example

{“X.”,
“XX”}
2
Returns: 5
Here one of the mountains is completely covered by the other. The five possible sequences are:
(0, 1), (0, 1)
(0, 1), (0, 0)
(0, 1), (1, 0)
(0, 0), (0, 1)
(1, 0), (0, 1)

数据范围

  • 画布长宽皆至五十
  • 1N501≤N≤50

分析

PART 1 找山峰

通过给出的图,我们可以先确定有一些地方是一定是有山峰的,假设为peakspeaks个位置,那么如何去算这个peakspeaks呢?
容易发现,一个点如果是山峰,当且仅当这个点是这一列最高点并且两边的最高点都不高于它。
这样就可以用非常简单的方法先求出peakspeaks

PART 2 转化问题

我们设一个共有tottot个格子是山,总共有N0N0座山,还有NN座山山峰的位置不确定(N即是N0peaksN0−peaks,注意这里的记法与题目给出的有所不同)。那么问题就转化成了我们给这tottot个格子从11~tot编号,有N0N0个相同的物品,一个格子可以放多个物品。有peakspeaks个格子至少要放一个。放完后,我们把每个物品放到盒子的编号提出来变成一个序列,求这个序列的种数。
刚刚应该注意到非常重要也是非常关键的一点,我们结合这个样例,因为盒子的序号顺序有差异的序列也算是不同的,因此,事实上可以把这N0N0个物品看作是不相同的,然后求它们放在盒子里的方案数。
问题已经到了这一步了,就可以开始思考容斥的做法了。

PART 3 容斥

按照套路,我们设g(x)g(x)为恰好有xx个有限定的盒子没有满足限定(即这x个盒子里没放一个物品)。
那么要求的答案就是totN0g(1)g(2)...g(picks)totN0−g(1)−g(2)−...−g(picks),即,总共的方案数是N0N0个物品,每个物品有都有tottot个盒子可以放,再减去恰好是11个盒子不满足条件,2个盒子不满足条件,…,pickspicks个盒子不满足条件的方案数。
当然g(x)g(x)不好求,那么我们可以设一个f(x)f(x)表示至少有xx个有限定的盒子没有满足限定。那么容易得出f(x)=(picksx)×(totx)N0,即,先选出xx个盒子不放任何东西,这样还剩下totx个盒子,也就是这N0N0个物品的选择。
再来看一看f(x)f(x)g(x)g(x)的关系:f(x)=picksk=x(kx)g(k)f(x)=∑k=xpicks(kx)g(k),即,对于恰好kk个限定盒不满足的情况,这k个位置的任意xx组合都会在f(x)中被计算g(k)g(k)次。
这样答案就可以这样表示:totN0f(1)+f(2)f(3)+...+(1)picksf(picks)totN0−f(1)+f(2)−f(3)+...+(−1)picksf(picks),即:

i=0peaks(peaksi)×(1)i×(toti)N0∑i=0peaks(peaksi)×(−1)i×(tot−i)N0

(感谢cly_none大佬指教)

参考程序

//tc is healthy, just do it
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MOD = 1000000009;
const int ArSize = 55;
int fac[ArSize], inv[ArSize];

class MountainsEasy {
private:
    int H, W;
    void init() {   /*预处理出50以内的阶乘及其逆元,后面算组合数会用到*/
        int i;
        for (fac[0] = i = 1; i <= 50; i++) fac[i] = (LL)i * fac[i - 1] % MOD;
        inv[50] = fast_pow(fac[50], MOD - 2);
        for (i = 49; i >= 0; i--) inv[i] = (LL)(i + 1) * inv[i + 1] % MOD;
    }
    int fast_pow(int bs, int ex) {  // 快速幂
        int res = 1;
        for (; ex > 0; ex >>= 1, bs = (LL)bs * bs % MOD) if (ex & 1) res = (LL)res * bs % MOD;
        return res;
    }
    int C(int n, int r) {   // 组合数
        return (LL)fac[n] * inv[r] % MOD * inv[n - r] % MOD;
    }
public:
    int countPlacements( vector <string> picture, int N );
};

int MountainsEasy::countPlacements(vector <string> picture, int N) {
    H = picture.size(), W = picture[0].length();
    int x, y, N0 = N;
    for (x = 0; x < W && picture[H - 1][x] == '.'; x++);
    if (x == W) return 0;
    else {
        int tot = 0;
        // 找确定的山峰个数
        for (; x < W; x++) {
            for (y = 0; y < H && picture[y][x] == '.'; y++);
            if (y == H) continue;
            if (!y || 
                (!x && (x + 1 == W || picture[y - 1][x + 1] == '.')) ||
                 (x + 1 == W && (!x || picture[y - 1][x - 1] == '.')) || 
                 (x && x + 1 < W && picture[y - 1][x - 1] == '.' && picture[y - 1][x + 1] == '.')
            )
                --N;
            tot += H - y;
        }
        if (N < 0) return 0;
        init();
        int peaks = N0 - N;
        LL res = 0;
        // 容斥部分,极其精简吧
        for (int i = 0; i <= peaks; i++)
            if (i & 1) res = (res + MOD - (LL)C(peaks, i) * fast_pow(tot - i, N0) % MOD) % MOD;
            else res = (res + (LL)C(peaks, i) * fast_pow(tot - i, N0) % MOD) % MOD;
        return (int)res;
    }
}

总结

首先这个原题的英文题面废话很多,很长,转化之后就很简单的一个意思。不过转化到物品不同这一性质其实不容易,因为之前抽象出来的问题描述的不是很好…(我的锅…)但是cly大佬还是一眼就看出来了,个人认为自己的抽象能力还有待提升。解决了计数,找山峰其实也是很一个很毒瘤的模拟题,一开始写的很麻烦,改来改去改了三次才想到这个简单的思路。总而言之,这题考验的还是你的抽象能力,是否能发现问题最本质的性质,无论是在求山峰还是算方案的时候都是很需要这种能力的。我认为这是道好题!

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内概要:本文围绕“基于数据驱动的Koopman算子的递归神经网络模型线性化”展开,旨在研究纳米定位系统的预测控制问题,并提供完整的Matlab代码实现。文章结合数据驱动方法与Koopman算子理论,利用递归神经网络(RNN)对非线性系统进行建模与线性化处理,从而提升纳米级定位系统的精度与动态响应性能。该方法通过提取系统隐含动态特征,构建近似线性模型,便于后续模型预测控制(MPC)的设计与优化,适用于高精度自动化控制场景。文中还展示了相关实验验证与仿真结果,证明了该方法的有效性和先进性。; 适合人群:具备一定控制理论基础和Matlab编程能力,从事精密控制、智能制造、自动化或相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①应用于纳米级精密定位系统(如原子力显微镜、半导体制造设备)中的高性能控制设计;②为非线性系统建模与线性化提供一种结合深度学习与现代控制理论的新思路;③帮助读者掌握Koopman算子、RNN建模与模型预测控制的综合应用。; 阅读建议:建议读者结合提供的Matlab代码逐段理解算法实现流程,重点关注数据预处理、RNN结构设计、Koopman观测矩阵构建及MPC控制器集成等关键环节,并可通过更换实际系统数据进行迁移验证,深化对方法泛化能力的理解。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值