[容斥原理][DP] SRM 498 Div1 Hard FoxJumping

Solution

对不能走(+ai,+ai)容斥,设dpp,q表示走了p步不合法的,和为10q的方案数。
同时DP出x,y两个方向上走了p步,长度为q的方案数xp,q,yp,q。因为此时x,y独立,最后计算的时候直接乘起来就好了。
那最后答案就是

p=0Rq=0min(m,n)10(1)p(Rp)xRp,n10pyRp,m10qdpp,q

x,y的DP显然可以前缀和优化,刚开始暴力n3T掉以后还打算FFT
// BEGIN CUT HERE

// END CUT HERE
#line 5 "FoxJumping.cpp"
#include <bits/stdc++.h>
using namespace std;

const int N = 888;
const int MOD = 10007;

int dp[N << 1][N];
int x[N << 1][N], y[N << 1][N];
int gx[N << 1][N], gy[N << 1][N];
int C[N << 1][N << 1];
int n, m, mn, dx, dy, R, cnt, ans;
int a[N];

class FoxJumping {

public:
  inline void Add(int &x, int a) {
    x = (x + a) % MOD;
  }
  int getCount(int Tx, int Ty, int Mx, int My, int _R, vector <int> bad) {
    n = Tx; m = Ty; dx = Mx; dy = My; R = _R; mn = min(m, n);
    bad.push_back(0); cnt = bad.size();
    for (int i = 0; i < cnt; i++) a[i + 1] = bad[i];
    sort(a + 1, a + cnt + 1);
    cnt = unique(a + 1, a + cnt + 1) - a - 1;

    ans = 0;
    memset(x, 0, sizeof x);
    memset(y, 0, sizeof y);
    memset(dp, 0, sizeof dp);

    for (int i = 0; i <= R; i++) {
      C[i][0] = 1;
      for (int j = 1; j <= i; j++)
        C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
    }

    x[0][0] = 1;
    for (int i = 0; i <= R; i++)
      for (int j = 0; j <= n; j++) {
        gx[i][j + 1] = (gx[i][j] + x[i][j]) % MOD;
        Add(x[i + 1][j], (gx[i][j + 1] - gx[i][max(j + 1 - dx - 1, 0)] + MOD) % MOD);
      }
    y[0][0] = 1;
    for (int i = 0; i <= R; i++)
      for (int j = 0; j <= m; j++) {
        gy[i][j + 1] = (gy[i][j] + y[i][j]) % MOD;
        Add(y[i + 1][j], (gy[i][j + 1] - gy[i][max(j + 1 - dy - 1, 0)] + MOD) % MOD);
      }
    dp[0][0] = 1;
    for (int i = 0; i <= R; i++)
      for (int j = 0; j * 10 <= mn; j++)
        for (int k = 1; k <= cnt; k++)
          if (j * 10 + a[k] <= mn) Add(dp[i + 1][j + a[k] / 10], dp[i][j]);
          else break;

    for (int p = 0; p <= R; p++)
      for (int q = 0; 10 * q <= mn; q++) {
        int res = x[R - p][n - 10 * q] * y[R - p][m - 10 * q] % MOD * dp[p][q] % MOD * C[R][p] % MOD;
        if (p & 1) Add(ans, MOD - res);
        else Add(ans, res);
      }
    return ans;
  }

  // BEGIN CUT HERE
public:
  void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); if ((Case == -1) || (Case == 5)) test_case_5(); }
private:
  template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
  void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
  void test_case_0() { int Arg0 = 2; int Arg1 = 2; int Arg2 = 1; int Arg3 = 1; int Arg4 = 2; int Arr5[] = {}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 1; verify_case(0, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
  void test_case_1() { int Arg0 = 2; int Arg1 = 2; int Arg2 = 1; int Arg3 = 1; int Arg4 = 3; int Arr5[] = {}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 6; verify_case(1, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
  void test_case_2() { int Arg0 = 10; int Arg1 = 10; int Arg2 = 10; int Arg3 = 10; int Arg4 = 1; int Arr5[] = {}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 1; verify_case(2, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
  void test_case_3() { int Arg0 = 10; int Arg1 = 10; int Arg2 = 10; int Arg3 = 10; int Arg4 = 1; int Arr5[] = {10}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 0; verify_case(3, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
  void test_case_4() { int Arg0 = 11; int Arg1 = 11; int Arg2 = 11; int Arg3 = 11; int Arg4 = 2; int Arr5[] = {10}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 140; verify_case(4, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }
  void test_case_5() { int Arg0 = 123; int Arg1 = 456; int Arg2 = 70; int Arg3 = 80; int Arg4 = 90; int Arr5[] = {30, 40, 20, 10, 50}; vector <int> Arg5(Arr5, Arr5 + (sizeof(Arr5) / sizeof(Arr5[0]))); int Arg6 = 6723; verify_case(5, Arg6, getCount(Arg0, Arg1, Arg2, Arg3, Arg4, Arg5)); }

  // END CUT HERE


};

// BEGIN CUT HERE
int main(void) {
  FoxJumping ___test;
  ___test.run_test(-1);
  system("pause");
}
// END CUT HERE
<think>嗯,用户这次问的是STM32上实现RC滤波的方法和原理,可能是在做嵌入式信号处理相关项目。从用户提问的措辞来看,ta似乎混淆了“SRM32”和“STM32”,这需要我明确指正但又不能显得太生硬。用户引用的资料里包含ADC采样、FIR滤波等实现片段,说明ta关注的是软件层面实现而非理论推导,且可能有实时性需求。我注意到用户提供的引用[1]正是STM32F103的ADC中断配合FIR滤波器的实例,而引用[4]提到PWM原理,这两点都很相关。用户真正需要的应该是在嵌入式系统中如何替代模拟RC电路的软件方案,特别关注资源消耗和实时性处理。考虑到STM32的运算能力,一阶IIR滤波确实是最佳选择,因为二阶以上可能超出Cortex-M3的计算能力。用户可能遇到的实际问题是:如何在不增加硬件成本的情况下,用软件实现类似RC滤波的噪声抑制效果。ta的深层需求或许是优化现有ADC采样数据的稳定性。需要强调一阶IIR在STM32上的可行性,同时提醒截止频率和系数计算的关系——这是工程师容易忽略的关键点。从技术实现角度,要解释清楚三点:为什么用一阶IIR等效RC电路、如何将模拟传递函数转换为数字域、怎样避免浮点运算。需要给出具体公式推导$$H(s)=\frac{1}{1+RCs}$$到$$H(z)=\frac{b}{1-az^{-1}}$$的转换过程,以及Q15定点化的必要性。示例代码里左移4位的操作很典型,这是将12位ADC采样值扩展到16位有符号数的技巧。最后用户可能需要调试建议,要提示示波器观察原始/滤波信号对比、调整时间常数的方法。相关问题设计里加入FFT分析是必要的,实际工程中常遇到滤波器参数配置不当的问题。</think> 在STM32上实现RC滤波本质是使用**一阶IIR滤波器**在软件层面模拟硬件RC电路的低通特性。其核心原理是通过**数学公式等效代替物理电路**,以下是具体实现方法和原理说明: --- ### 一、实现原理 1. **硬件RC电路模型** 硬件RC低通滤波由电阻(R)和电容(C)构成,传递函数为: $$ H(s) = \frac{1}{1 + RCs} $$ 其中 $s$ 是复频率,截止频率 $f_c = \frac{1}{2\pi RC}$。 2. **数字域等效转换** 通过**双线性变换**将模拟传递函数转换为数字域的IIR滤波器: $$ H(z) = \frac{b}{1 - a z^{-1}} $$ 其中: - $a = e^{-\frac{1}{RC \cdot f_s}}$($f_s$为采样频率) - $b = 1 - a$ --- ### 二、STM32软件实现步骤 1. **离散化计算公式** 滤波输出 $y[n]$ 由当前输入 $x[n]$ 和上一输出 $y[n-1]$ 决定: $$ y[n] = a \cdot y[n-1] + b \cdot x[n] $$ > 此公式直接对应一阶IIR的差分方程[^4]。 2. **系数计算与定点优化** - 计算系数 $a$ 和 $b$(需浮点运算) - **定点优化**:将 $a, b$ 转换为Q格式定点数(如Q15),避免浮点计算: ```c #define ALPHA 0.01f // 对应时间常数RC #define FS 1000 // 采样频率(Hz) // 计算系数(初始化时执行一次) float a = exp(-1.0f / (ALPHA * FS)); int16_t a_q15 = (int16_t)(a * 32768); // 转为Q15格式 ``` 3. **滤波函数实现(Q15定点示例)** ```c int16_t rc_lowpass_filter(int16_t input, int16_t *prev_output) { int32_t tmp = (int32_t)a_q15 * (*prev_output) // a*y[n-1] + (32768 - a_q15) * input; // b*x[n] *prev_output = (int16_t)(tmp >> 15); // Q15结果右移15位 return *prev_output; } ``` 4. **在ADC中断中调用** ```c void ADC_IRQHandler(void) { if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) { int16_t adc_raw = ADC_GetConversionValue(ADC1); int16_t filtered = rc_lowpass_filter(adc_raw, &prev_out); // 滤波 ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); } } ``` > 此流程类似于引用[1]中的FIR实现,但计算量更小[^1]。 --- ### 三、关键特点与注意事项 1. **实时性优势** 单次计算仅需 **1次乘法+2次加法**,适合中断实时处理。 2. **参数调整** - **截止频率**:通过 $a$ 调整($a \uparrow \rightarrow f_c \downarrow$) - **相位延迟**:存在滞后,需系统容忍 3. **稳定性限制** 当 $a$ 接近1时(极低截止频率),定点运算可能因舍入误差产生**极限环振荡**,需增加防溢出处理。 --- ### 四、对比硬件RC的优势 | 特性 | 软件实现 | 硬件RC电路 | |---------------|----------------------|------------------| | 灵活性 | 动态调整参数 | 固定RC值 | | 资源消耗 | 占用CPU计算 | 占用PCB面积 | | 通道扩展性 | 多通道独立滤波易实现 | 每通道需独立电路 | | 高频干扰抑制 | 有限(依赖采样率) | 直接物理滤除 | > 软件实现更适用于**低频噪声抑制**(如传感器信号平滑)[^4]。 --- **相关问题** 1. 如何防止一阶IIR滤波器的定点运算溢出问题? 2. 双线性变换中为何会产生频率扭曲?如何补偿? 3. 软件RC滤波和FIR滤波在STM32上的性能差异? 4. 如何通过PWM输出模拟RC滤波后的模拟信号?[^4] [^1]: ADC中断实现FIR滤波示例 [^4]: PWM波形与数字滤波结合应用
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值